Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cpanel Whm Laravel Package

gufy/cpanel-whm

Laravel package for interacting with cPanel and WHM APIs. Manage accounts, email, databases, domains, DNS and more through a clean, fluent PHP interface, with support for both cPanel and WHM endpoints, simple configuration, and straightforward installation via Composer.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and wire it up

composer require gufy/cpanel-whm

This is a Laravel 5-era package. On Laravel 5.5+ it may auto-discover; if not, add the service provider (and optionally a facade alias) manually in config/app.php:

'providers' => [
    // ...
    Gufy\CpanelPhp\Providers\LaravelServiceProvider::class,
],

2. Publish and configure

php artisan vendor:publish --provider="Gufy\CpanelPhp\Providers\LaravelServiceProvider"

You get a config/cpanel.php with host, port, username, password, token, auth_type, and debug. Drive it from .env:

CPANEL_HOST=server1.example.com   # use the hostname, not the IP
CPANEL_PORT=2087                  # 2087 = WHM SSL, 2086 = WHM plain
CPANEL_USERNAME=root
CPANEL_PASSWORD=                  # or use a token instead
CPANEL_TOKEN=
CPANEL_AUTH_TYPE=password         # or "token"

Two scopes matter from day one:

Scope Port Purpose
WHM 2087 Server-wide: create/suspend/terminate accounts, packages, resellers
cPanel 2083 Per-account: email, forwarders, DNS zones, login URLs, disk usage

3. First use case: smoke-test then get an SSO link

Instantiate directly (avoids guessing the container binding), point it at your server, and call a harmless WHM function:

use Gufy\CpanelPhp\Cpanel;

$cpanel = (new Cpanel())
    ->setHost(config('cpanel.host'))
    ->setPort(config('cpanel.port'))
    ->setUsername(config('cpanel.username'))
    ->setPassword(config('cpanel.password'));

$accounts = $cpanel->listaccts();   // method names mirror WHM API functions

Then use the most common day-one feature — logging a customer into cPanel without a password:

$url = $cpanel->getLoginUrl($username, 'cpanel');
return redirect($url);

Where to look first: the README for available methods, config/cpanel.php for auth options, and the Cpanel class itself to see how it wraps the HTTP call (you'll want to know this for mocking and timeouts).

Implementation Patterns

Wrap it in your own service, don't scatter it. Bind a thin repository to the container so tests and future client swaps stay easy:

class WhmClient
{
    public function __construct(private Cpanel $cpanel) {}

    public function provision(array $spec): array
    {
        return $this->cpanel->createacct([
            'username' => $spec['username'],
            'domain'   => $spec['domain'],
            'password' => $spec['password'],
            'plan'     => $spec['plan'],
        ]);
    }
}

Multi-server / multi-tenant. Because the setters are fluent, build a fresh instance per target server rather than mutating a singleton:

$client = (new Cpanel())
    ->setHost($server->hostname)
    ->setPort(2087)
    ->setUsername($server->whm_user)
    ->setToken($server->whm_token)   // token auth is preferable to password
    ->setAuthType('token');

Store server credentials (encrypted cast) in a servers table and cache one client per server.

Common WHM admin flows to build first:

$cpanel->listpkgs();                                   // hosting packages
$cpanel->createacct($params);                          // provision
$cpanel->suspendacct(['user' => $user, 'reason' => 'billing']);
$cpanel->unsuspendacct(['user' => $user]);
$cpanel->removeacct(['user' => $user, 'keepdns' => 0]);
$cpanel->changepackage(['user' => $user, 'pkg' => 'premium']);
$cpanel->passwd(['user' => $user, 'pass' => $newPassword]);

cPanel user-scope flows. Use the same fluent setup but target port 2083 and the account user; this is where getLoginUrl, email/forwarder creation, and disk-usage lookups live.

Push provisioning into jobs. createacct and removeacct are slow and can time out. Dispatch a queued job, store the raw response for auditability, and emit domain events (AccountCreated, AccountSuspended) after success — that's the pattern that makes this package feel like part of your app instead of a script.

Normalize the responses. WHM returns {metadata: {result: 1, ...}, data: {...}}, while cPanel API2 returns {cpanelresult: {data: [...], error: ...}}. Write one adapter that converts both into a ['ok' => bool, 'data' => array, 'error' => ?string] shape so your controllers don't branch on API version.

Testing. Don't hit a live WHM in tests. Subclass Cpanel and override the request method to return fixture JSON, or bind a fake WhmClient interface into the container. Keep a couple of recorded real responses (anonymized) as fixtures — the response wrappers are the easiest thing to get wrong.

Gotchas and Tips

  • It's a 2017 package with zero dependents. Treat it as a convenience wrapper, not infrastructure. Pin the version, expect illuminate/support constraints to fight Laravel 9+. On modern Laravel you'll likely fork it, loosen constraints, or reimplement the ~200 lines over Guzzle/Laravel Http. Budget for that up front.
  • HTTP 200 does not mean success. WHM and cPanel return errors inside the JSON body with a 200 status. Always check metadata.result / cpanelresult.error before assuming a create/suspend worked.
  • Auth type confusion. password and token are handled differently; if auth_type is token, set a token (not a password) and make sure your WHM user has API token access. Symptom of a mismatch: 401/403 that looks like a bad host.
  • Use the hostname, not the IP. cPanel/WHM certs are issued to the FQDN; hitting https://1.2.3.4:2087 triggers TLS verification errors. If you must, disable verification in the client config — but never in production.
  • Ports and firewall. 2087 is blocked by default on many hosts/VPCs. Test from inside the network first; a Connection refused is more often a security group than the package.
  • getLoginUrl links are single-use and short-lived. Don't cache or email them; redirect immediately. They're a great SSO primitive for a customer dashboard.
  • listaccts() returns every account on the server. On a busy box that's megabytes of JSON and a slow request. Use WHM's search/searchtype/page/chunk params rather than pulling everything and filtering in PHP.
  • Debug mode logs credentials. Turn CPANEL_DEBUG off in production and make sure the raw request (which includes the Authorization header) never hits your normal log channel.
  • Root credentials in .env are a liability. Prefer a dedicated API token tied to a minimal-privilege reseller if you only manage a subset of accounts, and rotate on a schedule.
  • Raw escape hatch. If a WHM function isn't wrapped, call it through the package's generic request/dynamic method (or drop to your own Guzzle call) rather than waiting for a release — the project is effectively unmaintained.
  • Extension point is subclassing. There are no macros or events in the package; if you need retries, timeouts, logging, or response normalization, put it in a subclass or a decorator you own, and keep the package itself untouched so you can swap it out later.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package