Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SoapFault exception cannot be caught when using SoapClient in Laravel #6618

Closed
dmgfjaved opened this issue Dec 10, 2014 · 27 comments
Closed

Comments

@dmgfjaved
Copy link

try {
$client = new SoapClient("wsdl-url-here",array('trace' => 1,'exceptions'=> true));
} catch (SoapFault $fault){
echo $fault->faultstring;
}

In the example above, if I have invalid WSDL URL, I am supposed to get SoapFault exception since I set exceptions to true. However, Laravel catches this as FATAL exception and the application crashes. This code works as expected outside of Laravel.

@dwightwatson
Copy link
Contributor

Are you in a namespaced file that has already included SoapClient? You may need to add use SoapFault; at the top of the document or add a backslash to the class name in the catch statement (\SoapFault $fault).

@dmgfjaved
Copy link
Author

Thanks for your response. SoapFault is an exception thrown by PHP SoapClient class (http://php.net/manual/en/class.soapfault.php). I have tried adding backslash but that didn't help. What I have found is that the SOAP exception is thrown and I can catch it, however, Laravel still crashes with FATAL SOAP exception. I have implemented the following workaround in my global.php to fix the issue temporarily.

App::fatal(function($exception)
{   //If SOAP Error is found, we don't want to FATALLY crash but catch it instead
    if(strpos($exception->getMessage(), 'SOAP-ERROR') !== FALSE)
    {
    return '';
    }
});

@RomainLanz
Copy link

If you catch all exception instead of catch SoapFault is it working?

try {
    $client = new SoapClient("wsdl-url-here", ['trace' => 1, 'exceptions' => true]);
} catch (Exception $e) {
    echo 'Catch it!';
}

@dmgfjaved
Copy link
Author

I have tried that as well, it still crashed with FATAL exception.

@RomainLanz
Copy link

Can you paste the complete exception's message?

@dmgfjaved
Copy link
Author

When I use invalid WSDL URL, this is the message I get without using any workaround:

Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_ERROR)
SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://www.example.com/v4_6_release/apis/1.5/ServiceTicketApi.asmx?wsdl' : failed to load external entity "https://www.example.com/v4_6_release/apis/1.5/ServiceTicketApi.asmx?wsdl"

@dwightwatson
Copy link
Contributor

Do you want to throw a backslash in front of @RomainLanz's solution too, the catch statement really should pickup on that exception.

@RomainLanz
Copy link

@dwightwatson He said that he tried: "I have tried adding backslash but that didn't help."

@dmgfjaved
Copy link
Author

Yes, tried both Exception and \Exception and get the same error as before.

@dwightwatson
Copy link
Contributor

I was under the impression he had added a backslash to the SoapFault, was suggesting that it be tried again with the raw Exception class.

@dmgfjaved
Copy link
Author

I am wondering if I am having the issue outlined here: https://bugs.php.net/bug.php?id=47584
I am not sure if Laravel uses xdebug

@dwightwatson
Copy link
Contributor

I believe the Homestead environment has XDebug but that isn't anything specific to Laravel. Looks like that bug could be the cause of your grief unfortunately.

@dmgfjaved
Copy link
Author

I am actually using XAMPP and have disabled xdebug completely in my php.ini, and that's why I was thinking it could be a Laravel issue. FYI- I tried the try/catch outside of Laravel within the same XAMPP environment and it works as expected (no FATAL crash)

@memtoko
Copy link

memtoko commented Dec 19, 2014

Laravel think that E_ERROR that genereted by SoapClient is a fatal error. So laravel will throw FatalException. It's happen before you catch that exception in L4.

@JoostK
Copy link
Contributor

JoostK commented Dec 19, 2014

Set your error_reporting to not include E_ERROR.

@martinezjc
Copy link

Same problem here "Symfony\Component\Debug\Exception\FatalErrorException' with message 'SOAP-ERROR: Parsing WSDL: Couldn't load from http:...."

@skuti974
Copy link

You have to disable your error_handler. I got this problem when i was coding my own framework. The error_handler by passing the try...catch.

@pushpinderbagga
Copy link

Have you tried catching \Exception instead of a \SoapFault?

@mdrost
Copy link

mdrost commented Feb 24, 2016

My workaround in App\Exceptions\Handler for console application:

    protected function shouldntReport(Exception $e)
    {
        if ($this->isSoapError($e)) {
            return true;
        }
        return parent::shouldntReport($e);
    }

    public function renderForConsole($output, Exception $e)
    {
        if ($this->isSoapError($e)) {
            return;
        }
        return parent::renderForConsole($output, $e);
    }

    private function isSoapError(Exception $e)
    {
        return strpos($e->getMessage(), 'SOAP-ERROR: Parsing WSDL:') !== false;
    }

@jarnovanleeuwen
Copy link
Contributor

jarnovanleeuwen commented Apr 2, 2016

Actually, the SoapFault is successfully caught. However, Laravel is handling the last error in its handleShutdown method. Therefore, clear the last error to avoid the fatal error exception:

try {
    return $this->client = new SoapClient($this->getWsdlUrl(), [
        'cache_wsdl' => WSDL_CACHE_NONE,
        'exceptions' => true
    ]);
} catch (SoapFault $exception) {
    Log::error($exception);

    error_clear_last(); // The solution.
}

Tested in Laravel 5.2.

EDIT: Still working in Laravel 5.7. Also, updated comment to use error_clear_last() introduced in PHP 7. For versions below PHP 7.0 replace error_clear_last() with:

set_error_handler('var_dump', 0); // Never called because of empty mask.
@trigger_error("");
restore_error_handler();

@ehsanhoushmand
Copy link

Have you tried catching \Throwable instead of a \SoapFault?

@Triplkrypl
Copy link
Contributor

Triplkrypl commented Feb 7, 2018

hi
i have this problem and it is uncatchable i think.

set_error_handler('var_dump', 0); // Never called because of empty mask.
@trigger_error("");
restore_error_handler();

This is working solution, soap thow exception and error than can not be catch.
In catch SoapFault on php 7 can do this:

error_clear_last();

Less code.

@jmfederico
Copy link

The solution is to actually ask the Soap client to throw a SoapFault instead of reporting an E_ERROR.

When the Soap client reports an E_ERROR, there is nothing for you to catch.

To fix this initialise you SoapClient like this:

        $clientOptions = array(
            'exceptions' => true,
        );

        try {
            $client = new \SoapClient("foo.wsdl", $clientOptions);
        } catch (\SoapFault $e) {
            // Do what you need to do!;
        }

        try {
            $result = $client->__soapCall($method, $data);
        } catch (\SoapFault $e) {
            // Do what you need to do!;
        }

@Enormity
Copy link

Enormity commented Nov 1, 2019

The solution is to actually ask the Soap client to throw a SoapFault instead of reporting an E_ERROR.

When the Soap client reports an E_ERROR, there is nothing for you to catch.

To fix this initialise you SoapClient like this:

        $clientOptions = array(
            'exceptions' => true,
        );

        try {
            $client = new \SoapClient("foo.wsdl", $clientOptions);
        } catch (\SoapFault $e) {
            // Do what you need to do!;
        }

        try {
            $result = $client->__soapCall($method, $data);
        } catch (\SoapFault $e) {
            // Do what you need to do!;
        }

This is the correct solution. Thank you.

@bhartvigsen
Copy link

bhartvigsen commented Feb 4, 2020

This is the correct solution. Thank you.

Have you tried this? It doesn't actually work. In fact I've tried every single workaround on this issue, nothing actually works.

Bumping this issue, this is an ongoing problem even in 6.4. We need a reasonable way to override Laravel's exception handling.

@plooody
Copy link

plooody commented Oct 8, 2020

Actually, the SoapFault is successfully caught. However, Laravel is handling the last error in its handleShutdown method. Therefore, clear the last error to avoid the fatal error exception:

try {
    return $this->client = new SoapClient($this->getWsdlUrl(), [
        'cache_wsdl' => WSDL_CACHE_NONE,
        'exceptions' => true
    ]);
} catch (SoapFault $exception) {
    Log::error($exception);

    error_clear_last(); // The solution.
}

Tested in Laravel 5.2.

EDIT: Still working in Laravel 5.7. Also, updated comment to use error_clear_last() introduced in PHP 7. For versions below PHP 7.0 replace error_clear_last() with:

set_error_handler('var_dump', 0); // Never called because of empty mask.
@trigger_error("");
restore_error_handler();

1st step: Make sure you include
use SoapFailt;
use SoapClient;
use Log;

2nd step:
Use the above example from the quoted guy

3rd step: I had to change his code a little. Added a backslach like this "...} catch (\SoapFault $exception) {..."

@BasvanH
Copy link

BasvanH commented Oct 9, 2021

When using 'exceptions' => true, the $this->client->__getLastRequest() is null.

When using 'exceptions' => false, the $this->client->__getLastRequest() is filled, but cant get to it because I cant catch it because its captured by Symfony\Component\ErrorHandler\Error\FatalError.

Any idea how I can get to $this->client->__getLastRequest() with 'exceptions' => false` ??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests