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

Nusoap Laravel Package

nusphere/nusoap

nusphere/nusoap is a PHP SOAP toolkit for building and consuming SOAP web services without PHP's SOAP extension. It offers client and server classes, WSDL generation/parsing, and a lightweight, dependency-free way to integrate legacy SOAP APIs into Laravel or plain PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and verify autoloading first — this is the step that bites.

composer require nusphere/nusoap

The package is from 2015 and has no PSR-4 structure; it ships one procedural file that declares global classes (nusoap_client, soap_server, soapval, soap_fault/nusoap_fault, wsdl, nusoap_base). Before writing any code, confirm Composer actually registered them:

cat vendor/nusphere/nusoap/composer.json      # look for "autoload" (classmap or files)
find vendor/nusphere/nusoap -name 'nusoap*.php'
php -r "require 'vendor/autoload.php'; var_dump(class_exists('nusoap_client'));"

If the package declares no autoload block, Composer installs the files but autoloading fails. Fix it once in composer.json of your app and re-dump:

"autoload": { "classmap": ["vendor/nusphere/nusoap/lib/nusoap.php"] }

Then smoke-test the file against your PHP version, because "some fixes" in this fork targets PHP 5.6/7-era syntax:

php -l vendor/nusphere/nusoap/lib/nusoap.php

First use case: call a legacy WSDL endpoint. NuSOAP's whole reason to exist is talking to SOAP services from pure PHP without ext-soap — useful for .asmx services and old enterprise endpoints.

$client = new nusoap_client('https://legacy.example.com/Service.asmx?WSDL', 'wsdl');
$client->soap_defencoding = 'UTF-8';
$client->timeout = 30;

$result = $client->call('GetCustomer', ['CustomerId' => 123]);

if ($err = $client->getError()) {
    // transport / WSDL / serialization error (string)
} elseif ($client->fault) {
    // application-level SOAP fault: $client->faultcode, $client->faultstring
} else {
    // $result is an assoc array mirroring the response element
}

$client->request and $client->response hold the raw XML after every call — dump them immediately if anything looks wrong. This is the fastest debugging loop the package offers.

Implementation Patterns

Wrap it once, inject config, never touch nusoap_client in controllers. The class is global, stateful, and does blocking I/O, so it is hostile to testability. Bind a gateway as a singleton in a Laravel service provider and keep the endpoint/WSDL/credentials in config/services.php.

class SoapGateway
{
    private nusoap_client $client;

    public function __construct(array $config)
    {
        $this->client = new nusoap_client($config['wsdl'], 'wsdl');
        $this->client->soap_defencoding = 'UTF-8';
        $this->client->decode_utf8    = false;   // see Gotchas
        $this->client->timeout        = $config['timeout'] ?? 30;
        $this->client->response_timeout = $config['timeout'] ?? 30;

        if (! empty($config['user'])) {
            $this->client->setCredentials($config['user'], $config['pass'], 'basic');
        }
        $this->client->setCaching(false);
    }

    public function call(string $operation, array $params = [], ?string $soapHeaders = null)
    {
        $result = $soapHeaders
            ? $this->client->call($operation, $params, '', '', $soapHeaders)
            : $this->client->call($operation, $params);

        if ($err = $this->client->getError()) {
            throw new SoapTransportException($operation, $err, $this->client->request, $this->client->response);
        }
        if ($this->client->fault) {
            throw new SoapFaultException($operation, $this->client->faultcode, $this->client->faultstring);
        }
        return $result;
    }
}

Injecting the error XML into the exception message is what makes production incidents diagnosable a year later.

Non-WSDL mode is the escape hatch. Many internal services expose a broken, gated, or gigantic WSDL. NuSOAP happily builds envelopes without one — this is its strongest practical feature:

$client = new nusoap_client(false);          // no WSDL, no fetch
$client->setEndpoint('https://host/Service.asmx');
$client->soap_defencoding = 'UTF-8';

$result = $client->call(
    'GetCustomer',                            // operation
    ['CustomerId' => 123],                    // params
    'urn:example:service',                    // namespace
    'urn:example:service/GetCustomer'         // SOAPAction — required by .asmx/.NET
);

Skipping the WSDL fetch also removes one HTTP round-trip and one failure mode from every request.

SOAP headers (WS-Security, session tokens) go in the 5th argument of call(), as a raw XML string — there is no addSoapHeader() you'd recognise from ext-soap:

$header = '<wsse:Security xmlns:wsse="..."><wsse:UsernameToken>...</wsse:UsernameToken></wsse:Security>';
$client->call('Op', $params, 'urn:ns', 'urn:ns/Op', $header);

Note the distinction: setHeaders() sets HTTP headers, call($op, $p, $ns, $action, $headers) sets the SOAP header block.

Explicit types for arrays and nillable/typed values use soapval. Reach for it when the server rejects a plain PHP array or when the WSDL expects xsi:type:

$items = array_map(
    fn ($row) => new soapval('Item', 'ItemType', ['Id' => $row['id']], false, 'urn:ns'),
    $rows
);
$params = ['Items' => new soapval('Items', 'ArrayOfItemType', $items)];

Exposing an endpoint (server mode) in a Laravel route — useful for shimming a SOAP contract over an existing JSON API:

Route::post('/soap/legacy', function (Request $request) {
    $server = new soap_server();
    $server->soap_defencoding = 'UTF-8';
    $server->configureWSDL('legacy', 'urn:legacy', url('/soap/legacy'));
    $server->wsdl->schemaTargetNamespace = 'urn:legacy';
    $server->register(
        'legacyGetOrder',
        ['id' => 'xsd:string'],
        ['return' => 'xsd:string'],
        'urn:legacy'
    );

    ob_start();                       // service() may echo/emit headers itself
    $server->service($request->getContent());
    $body = ob_get_clean();

    return response($body, 200)->header('Content-Type', 'text/xml; charset=UTF-8');
})->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

Read the raw body from $request->getContent() — never $HTTP_RAW_POST_DATA, which was removed in PHP 7.

Testing. You cannot mock NuSOAP's transport (it uses curl/file_get_contents internally). Mock your SoapGateway at the boundary and write a small number of contract tests against a real or recorded endpoint: capture $client->request/$client->response once, commit them as fixtures, and assert on the request envelope shape rather than on the parsed array.

Gotchas and Tips

Check errors in the right order. call() returns null on a transport error and an array on a fault — a falsy check conflates the two and with a legitimately empty response. Always:

if ($err = $client->getError()) { /* transport */ }
elseif ($client->fault)         { /* application fault */ }
else                            { /* $result */ }

Encoding double-decode. The default decode_utf8 = true runs utf8_decode() over response strings; if your server already returns UTF-8 (most do), accented characters become mojibake. Set decode_utf8 = false and soap_defencoding = 'UTF-8' unless you are talking to a genuinely Windows-1252 service. Related: utf8_encode/utf8_decode are deprecated in PHP 8.2, so old NuSOAP paths will emit notices.

PHP 8 compatibility is not guaranteed. Pre-8-era NuSOAP used each(), create_function(), and assignments to undeclared properties. Under PHP 8.x you'll see "Creation of dynamic property … is deprecated" (fatal in 9), and removed functions are instant fatals. Run your first call with error_reporting(E_ALL) and a strict deprecation log before shipping. If you hit removed functions, vendor the file and patch it — the upstream repo is dormant.

WSDL caching writes to disk. When caching is enabled NuSOAP writes WSDL/XML to cacheDir, historically defaulting to the current working directory. In read-only containers this fails silently and re-fetches on every request. Set $client->setCaching(false) for short-lived PHP-FPM requests, or point cacheDir at storage_path('app/soap-cache').

No namespaces means collision risk. These are global classes. If any dependency also bundles NuSOAP (or you have two copies in vendor/), Composer reports "ambiguous class resolution" and the first-loaded copy wins — which may not be the one you patched. composer dump-autoload -o with --classmap-authoritative makes this loud rather than silent.

SOAP 1.1 only. NuSOAP emits SOAP 1.1 envelopes. Services that require SOAP 1.2 (application/soap+xml, different fault model) will reject requests regardless of correct parameters. Detect this early: if the WSDL soap12:binding is the only binding, this package is the wrong tool.

TLS and proxies. For self-signed internal endpoints you must go through curl, not the default stream transport:

$client->setUseCurl(true);
$client->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
$client->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
$client->setHTTPProxy($host, $port, $user, $pass);

Keep verification on for anything public; disable only behind a documented internal CA exception.

Complex responses aren't objects. Results are nested associative arrays keyed by the response element names. Don't assume the shape from the WSDL — json_encode($result) on the first real response, then map into a DTO. Watch for single-element arrays arriving as scalars (a classic SOAP quirk), and normalise before handing data to the rest of the app.

Log getDebug() on failure only. $client->getDebug() returns wire-level traces including full envelopes; it is gold in an incident and a PII leak in normal logs. Gate it behind your exception path or a config flag, and scrub credentials.

Pin and isolate. Last release was 2015 with effectively no dependents. Commit composer.lock, pin the exact version, and keep every call behind your gateway interface so migrating to ext-soap or phpro/soap-client later is a one-class change. If you need real WS-Security, SOAP 1.2, or MTOM, budget for that migration now rather than patching this fork.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console