Jump to content

Bug WHMCS-25204


Recommended Posts

I have reported the following on 19th Feb 2026 :

== Affected Version ==
WHMCS 9.0.1

== Description ==
When a client attempts to upgrade an existing yearly/recurring service to a one-time (lifetime) service, WHMCS throws a fatal DivisionByZeroError in includes/upgradefunctions.php inside SumUpPackageUpgradeOrder().
This happens on the latest WHMCS version running on PHP 8.3 and occurs even with all custom hooks/modules disabled, indicating a core issue.

This was working fine with PHP 7.4

ex :
Error: DivisionByZeroError: Division by zero in public_html/includes/upgradefunctions.php:0 Stack trace: #0 public_html/upgrade.php(0): SumUpPackageUpgradeOrder('9043', 10, 'monthly', '') #1 {main}

== Steps to Reproduce ==
Use the latest WHMCS version on PHP 8.3.
Create a recurring product (e.g., yearly billing cycle).
Create a second product with pay type “One Time”.
Set up an upgrade path from the yearly product to the one-time product.
Log in as a client with the yearly service.
Go to Client Area ? Upgrade/Downgrade and attempt to upgrade to the one-time product.
The upgrade page fails with a fatal error.

== Expected Result ==
The upgrade page should load normally

== PHP Version ==
8.3

== Severity ==
High 

This was confirmed to be a bug [ case WHMCS-25204 ].

Since then, two minor versions (WHMCS v9.0.2 & v9.0.3) were released, and this is not fixed yet!

Link to comment
Share on other sites

It's unfortunate that they are still not fixed it

If you are affected, You should be able to handle this with a hook till they come up with a permanent solution.  

I had done some hook for upgrade handling in the past, so it should be possible. 

Link to comment
Share on other sites

  • 1 month later...
2 hours ago, (Amr) said:

Any update on this ?

I have not tested this because I'm not using 9.x but this is an AI generated response that you could try on a test install by adding a hook and a small amount of code to clientareaproductdetails.tpl

<?php
/**
 * Fix: DivisionByZeroError when upgrading to a one-time product
 * Affected: WHMCS 9.x + PHP 8.x — upgradefunctions.php::SumUpPackageUpgradeOrder()
 *
 * Root cause: PHP 8.x throws a DivisionByZeroError where PHP 7.4 silently
 * returned 0. When upgrading to a one-time product, WHMCS attempts to
 * divide by the billing cycle days, which is 0 for one-time products.
 *
 * Save as: /includes/hooks/fix_upgrade_onetime_division.php
 */

// Hook files are loaded before upgrade.php runs its calculations,
// so we can register an exception handler here at file level to
// intercept the DivisionByZeroError before it becomes a fatal crash.
if (
    isset($_SERVER['SCRIPT_FILENAME']) &&
    basename($_SERVER['SCRIPT_FILENAME']) === 'upgrade.php'
) {
    // Capture any existing handler so we can chain it for unrelated errors
    $previousUpgradeExceptionHandler = set_exception_handler(null);

    set_exception_handler(function (\Throwable $e) use ($previousUpgradeExceptionHandler) {

        // Only intercept the specific bug — let everything else propagate normally
        if (
            $e instanceof \DivisionByZeroError &&
            strpos($e->getFile(), 'upgradefunctions.php') !== false
        ) {
            $serviceId = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : 0;
            header(
                'Location: clientarea.php?action=productdetails'
                . '&id=' . $serviceId
                . '&upgrade_error=onetime'
            );
            exit;
        }

        // Not our error — pass to the previous handler or PHP default
        if (is_callable($previousUpgradeExceptionHandler)) {
            call_user_func($previousUpgradeExceptionHandler, $e);
        } else {
            restore_exception_handler();
            throw $e;
        }
    });
}

/**
 * After the redirect, display a clear notice on the product details page
 * so the client knows what happened and what to do next.
 */
add_hook('ClientAreaPageProductDetails', 1, function ($vars) {
    if (empty($_GET['upgrade_error']) || $_GET['upgrade_error'] !== 'onetime') {
        return [];
    }

    return [
        'upgradeOnetimeError' => true,
        'upgradeOnetimeMessage' => 'Upgrading to a one-time payment product is not '
            . 'supported via the self-service upgrade tool. Please contact support '
            . 'and we will arrange this for you manually.',
    ];
});

 

Add to clientareaproductdetails.tpl

{if $upgradeOnetimeError}
    <div class="alert alert-warning">
        {$upgradeOnetimeMessage}
    </div>
{/if}

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use & Guidelines and understand your posts will initially be pre-moderated