Quantcast
Channel: DaHaiz' Programmier-Tagebuch
Viewing all articles
Browse latest Browse all 10

Magento Paypal IPN GnuTLS Fehler

$
0
0

Nachdem ich nun einen vollen Tag damit verbracht habe, die Instant Payment Notifications in einem Magento Shop zum Laufen zu bringen, möchte ich diese Lösung hier teilen, um auch anderen Verzweifelten zu helfen. Der ominöse Fehler lautet “GnuTLS recv error (-9): A TLS packet with unexpected length was received”. Grundsätzlich scheint das Problem bei der cURL Extension bzw. bei der verwendeten SSL-Library beheimatet zu sein. Die SSL Implementationen verschiedener Server sind laut folgendem Kommentar einer Mailinglist nicht dem TLS Protokol entsprechend, womit die Library GnuTLS nicht zurecht kommt:

Several sites terminate the TLS connection without following the TLS
protocol (i.e. sending closure alerts), but rather terminate the TCP
connection directly. This is a relic of SSLv2 and it seems other
implementations ignore this error. GnuTLS doesn’t and thus prints
this error. You could ignore it, but then you could not distinguish
between a premature connection termination (i.e. by someone injecting
a stray TCP termination packet) and normal termination.

Wer also bei seiner cURL Installation, GnuTLS verwendet bekommt den obigen Fehler zu sehen.

Nach vielem erfolglosem Herumprobieren mit verschiedenen cURL Optionen, habe ich mich dann dazu entschlossen das ganze isoliert mit dem Zend_Http_Client und dem Socket Adapter zu versuchen. Das klappte ohne Probleme und ich entschloss mich den Magento Code entsprechend anzupassen. Die betreffende Datei ist unter /app/code/core/Mage/Paypal/Model/Ipn.php zu finden. Die Methode _postBack ist wie folgt anzupassen:

    /**
     * Post back to PayPal to check whether this request is a valid one
     *
     * @param Zend_Http_Client_Adapter_Interface $httpAdapter
     */
    protected function _postBack(Zend_Http_Client_Adapter_Interface $httpAdapter)
    {
    		/* MAGENTO CODE - DOESNT WORK!
            $sReq = '';
            foreach ($this->_request as $k => $v) {
                $sReq .= '&'.$k.'='.urlencode(stripslashes($v));
            }
            $sReq .= "&cmd=_notify-validate";
            $sReq = substr($sReq, 1);
            $this->_debugData['postback'] = $sReq;
            $this->_debugData['postback_to'] = $this->_config->getPaypalUrl();
            $request = $httpAdapter->write(Zend_Http_Client::POST, $this->_config->getPaypalUrl(), '1.1', array(), $sReq);
            */

    		/* OWN CODE */
	    	$httpClient = new Zend_Http_Client($this->_config->getPaypalUrl());

			ksort($this->_request);

			$httpClient->setMethod(Zend_Http_Client::POST);

			$httpClient->setParameterPost($this->_request);
			$httpClient->setParameterPost("cmd","_notify-validate");

			/* END OWN CODE */

            try {
            	/* MAGENTO CODE - DOESNT WORK
                $response = $httpAdapter->read();
                */

            	/* OWN CODE */
            	$response = $httpClient->request();
            	/* END OWN CODE */

            } catch (Exception $e) {
                $this->_debugData['http_error'] = array('error' => $e->getMessage(), 'code' => $e->getCode());
                throw $e;
            }
            $this->_debugData['postback_result'] = $response;

            /* MAGENTO CODE - DOESNT WORK
            $response = preg_split('/^\r?$/m', $response, 2);
            $response = trim($response[1]);
            */

            if ($response/* OWN CODE*/->getBody()/* END OWN CODE */ != 'VERIFIED') {
                throw new Exception("PayPal IPN postback failure. See " . self::DEFAULT_LOG_FILE . " for details.".$request);
            }
            unset($this->_debugData['postback'], $this->_debugData['postback_result']);
    }

Es ist freilich nicht die sauberste Lösung, aber es funktioniert, was im Moment das wichtigste ist. Weiterhin ist meiner Meinung nach der Varien_Http_Adapter_Curl, den Magento normalerweise verwendet, sowieso nicht die ideale Lösung, da alles wichtige bereits der Zend_Http_Client bereitstellt. Statt also die die low-level Logik selbst zu implementieren, den Query-String aufzubauen, halte ich es für sinnvoller den Zend_Http_Client zu verwenden. Die Zend Library ist in Magento sowieso vorhanden, also wieso diese nicht benutzen?


Viewing all articles
Browse latest Browse all 10

Latest Images





Latest Images