Standalone PHP CLI for managing OpenEMR users — what bin/console openemr:user would be if it existed upstream. Designed for operators bringing up an account on a freshly-restored database dump, and for general user administration across forks (vanilla openemr/openemr, openemr-internal, customer forks).
Distributed as a single PHAR. Runs against any OpenEMR install from rel-702 through master.
Privileges. This CLI writes directly to the
usersandusers_securetables (and thegacl_*/groupstables when registering group membership). It bootstraps OpenEMR with$ignoreAuth = trueand deliberately bypasses the OpenEMR ACL — there is no logged-in user and no permission check. Run it only as an operator who already has DB write access to the OpenEMR site, and treat each invocation the same way you'd treat direct SQL against those tables.
Grab the PHAR from the latest release and drop it next to (or inside) the OpenEMR install:
curl -L -o oce-manage-users.phar \
https://github.com/opencoreemr/oce-cli-manage-users/releases/latest/download/oce-manage-users.phar
chmod +x oce-manage-users.pharOr install from source for development:
git clone https://github.com/opencoreemr/oce-cli-manage-users
cd oce-cli-manage-users
composer install
./bin/oce-manage-users listTo smoke-test the CLI against a real OpenEMR install in Docker:
task tools:install # one-time: pulls openemr/openemr into tools/openemr/vendor
task dev:start # bring up openemr + mysql + phpmyadmin (random loopback ports)
task dev:port # show the assigned host port
task exec -- user:list # run any CLI subcommand inside the containerThe CLI source is bind-mounted into the container at /var/www/localhost/htdocs/openemr/oce-cli-manage-users, so edits on the host are reflected immediately. See Taskfile.yml for the full task list.
Every command takes:
| Option | Default | Notes |
|---|---|---|
--openemr-path=<path> |
/var/www/localhost/htdocs/openemr |
Path to OpenEMR root (must contain interface/globals.php) |
--site=<name> |
default |
OpenEMR site (sites/<name>/sqlconf.php) |
Set or randomize a user's password.
# Prompt for the new password
oce-manage-users.phar user:reset-password --user=admin
# Provide it on the command line (visible in process list — prefer prompt or --random)
oce-manage-users.phar user:reset-password --user=admin --password='hunter2'
# Generate a random password and print it once to stdout
oce-manage-users.phar user:reset-password --user=admin --randomUpdates users_secure.password, stamps last_update_password = NOW(), and clears login_fail_counter and auto_block_emailed.
Create a new user.
# Authorized provider — defaults to the Administrators ACL group.
oce-manage-users.phar user:create \
--username=alice \
--password='sekret' \
--firstname=Alice \
--lastname=Liddell \
--email=alice@example.com \
--authorized \
--active
# Non-authorized user — must specify at least one --group.
oce-manage-users.phar user:create \
--username=bob \
--password='sekret' \
--firstname=Bob \
--lastname=Brown \
--group=Clinicians
# Multiple groups — repeat --group.
oce-manage-users.phar user:create \
--username=carol \
--password='sekret' \
--firstname=Carol \
--lastname=Carter \
--group=Administrators \
--group=CliniciansDefaults: --active is on, --authorized is off. Inserts into users and users_secure, backfills users.uuid if OpenEMR\Common\Uuid\UuidRegistry is available, and performs both group registrations OpenEMR's auth flow requires:
- gAcl (
gacl_aro+gacl_groups_aro_map) viaAclExtended::setUserAro, controlled by--group=<title>(repeatable). Required unless--authorizedis set, in which case it defaults toAdministrators. - Legacy
groupstable (the flat(name, user)mapping read byUserService::getAuthGroupForUserduring auth) via--legacy-group=<name>(defaultDefault). The auth flow rejects login with the sameerror=1redirect when this row is missing, even with a correct ACL ARO — it's a separate, older grouping system that OpenEMR still consults.
Without both registrations the user has a valid credential but cannot log in.
List users as a table.
oce-manage-users.phar user:list
oce-manage-users.phar user:list --active-only
oce-manage-users.phar user:list --inactive-only
oce-manage-users.phar user:list --lockedColumns: id, username, fname, lname, active, authorized, last_update_password, login_fail_counter.
Set users.active = 1. Optionally also set users.authorized = 1.
oce-manage-users.phar user:activate --user=alice
oce-manage-users.phar user:activate --user=alice --authorizedIdempotent.
Clear the lockout counter.
oce-manage-users.phar user:unlock --user=aliceSets users_secure.login_fail_counter = 0, last_login_fail = NULL, auto_block_emailed = 0. Idempotent.
For an existing stack of your own, copy the PHAR into the OpenEMR container and exec it:
docker compose cp oce-manage-users.phar openemr:/tmp/oce-manage-users.phar
docker compose exec -T openemr php /tmp/oce-manage-users.phar user:listOr mount it into the container via a compose.override.yml:
services:
openemr:
volumes:
- ./oce-manage-users.phar:/usr/local/bin/oce-manage-users.phar:roFor local dev/iteration on this CLI itself, use the bundled task dev:start workflow described above — it brings up OpenEMR's development-easy stack with the CLI source bind-mounted in.
Designed and tested against OpenEMR rel-702 through master. The only OpenEMR APIs this CLI touches are:
interface/globals.php(bootstrap)OpenEMR\Common\Auth\AuthHash::passwordHash()(password hashing — same signature in 7.2 and master)OpenEMR\Common\Uuid\UuidRegistry(if present — graceful fallback if not)sqlQuery,sqlStatement,sqlInsert,sqlFetchArray(since pre-7.0)
No dependence on bin/console, OEModule autoload, or anything that varies between forks.
- ACL groups,
users_facility, MFA management — separate commands later - LDAP / external auth backends
- Bulk operations (CSV, etc.)
- Wrapping the CLI in a docker image
GPL-3.0-or-later.