Wednesday 22 June 2011

Cannot restart apache in Ubunbu

I have issues from time to time with this command:

/etc/init.d/apache2 restart

I have even tried to kill the process with a ps -9 and still no luck.

I finally figured it out:

sudo /usr/sbin/apache2ctl restart

Saturday 18 June 2011

Reflection on using PHP's SoapClient

One of the great things about using PHP is the sheer number of built in functions (BIFs). Unfortunately though, some of the functions are not documented that well. Take the SoapClient class for example. I just spent a few hours today trying to configure it, so I'm posting up my experience so hopefully others don't have to spent those hours.

The problem:

I am trying to connect to a web service for a third party, and here is the bit of the wsdl that is interesting:

<wsdl:definitions targetNamespace="http://questionmark.com/QMWISe/">
...
<s:element name="Security" type="tns:SecurityHeader"/><s:complexType name="SecurityHeader"><s:sequence><s:element minOccurs="0" maxOccurs="1" name="ClientID" type="s:string"/><s:element minOccurs="0" maxOccurs="1" name="Checksum" type="s:string"/></s:sequence><s:anyAttribute/></s:complexType>
...
</wsdl>

When I make a call, I have to construct the header according to this:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:qmw="http://questionmark.com/QMWISe/">
   <soap:Header>
      <qmw:Security>
         <!--Optional:-->
         <qmw:ClientID>id</qmw:ClientID>
         <!--Optional:-->
         <qmw:Checksum>hash</qmw:Checksum>
      </qmw:Security>
   </soap:Header>
   <soap:Body>
       ...
   </soap:Body>
</soap:Envelope>

Simply enough right? Well not with the way SoapClient is structured.

This was what I had initially:

In client code:
 $this->client = new SoapClient(null, $this->constructParams());
 $this->client->__setSoapHeaders(new SoapHeader($this->targetNamespace, "Security",
            new SoapVar(new Security($this->username, $this->getMd5Hash()), SOAP_ENC_OBJECT));

In class Security:
class Security {

    function Security($clientId, $md5Hash) {
        $this->ClientID = $clientId;
        $this->Checksum = $md5Hash;
    }
}

Since we're using the SOAP_ENC_OBJECT flag which will tell PHP to use the variable name of the Security object, everything should be good to go right? Wrong. This is what it spits out:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://questionmark.com/QMWISe/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
      <env:Header>
            <ns1:Security>
                  <ClientID>id</ClientID>
                  <Checksum>hash</Checksum>
            </ns1:Security>
      </env:Header>
      <env:Body>
           ...
      </env:Body>
</env:Envelope>

Notice the difference? It's missing the namespace declaration for <ClientID> and <Checksum>, which leads to web service server complaining when we send out the request.


The solution:

So rather than using the docs from PHP, this is what I did to get around the issue:

new SoapHeader($this->targetNamespace, "Security",
            new SoapVar(array("ns1:ClientID" => $this->username, "ns1:Checksum" => $this->getMd5Hash()), SOAP_ENC_OBJECT));

The only issue here is that we are coding the ns1 namespace in the parameters. Although the namespace prefix won't change it just annoys me that I have to introduce this workaround in there to fix the issue. This is a workaround because it appears there is a PHP bug filed for this misbehavior:

When we do that, we see the correct behavior:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://questionmark.com/QMWISe/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
      <env:Header>
            <ns1:Security>
                  <ns1:ClientID>id</ns1:ClientID>
                  <ns1:Checksum>hash</ns1:Checksum>
            </ns1:Security>
      </env:Header>
      <env:Body>
         ...
      </env:Body>
</env:Envelope>

Problem with PHP's SoapClient and the hash symbol

I am writing an integration piece with a Learning Management System (LMS) called QuestionMark, and I was using PHP's out of the box SoapClient to retrieve information from a web service, but I kept getting this message after checking all my other parameters were correct:

Server did not recognize the value of HTTP Header SOAPAction: http://questionmark.com/QMWISe/#GetParticipant.

It turns out that I needed to specify the correct version of SOAP in order for this to work. So to fix this issue, add this to the array while constructing the SoapClient object:

'soap_version' => SOAP_1_2

More context:

$params = array('location' => $this->wsdlUrl, 'uri' => $this->targetNamespace, 'soap_version' => SOAP_1_2, 'trace' => 1)

$this->client = new SoapClient(null, $params);

Sunday 5 June 2011

FIXED: CUPS print server unable to start

Stranglely I started having problems with the CUPS print server when I installed Zend Server and Zend Studio on my Ubuntu 11.04 system. This was what the logs were showing:


Jun  3 10:36:29 acjcm3c kernel: [  527.087977] type=1400 audit(1307122589.944:318): apparmor="DENIED" operation="file_mmap" parent=1 profile="/usr/sbin/cupsd" name="/usr/local/zend/lib/liblber-2.4.so.2" pid=5107 comm="cupsd" requested_mask="m" denied_mask="m" fsuid=0 ouid=0
Jun  3 10:36:35 acjcm3c kernel: [  532.130427] type=1400 audit(1307122594.994:319): apparmor="STATUS" operation="profile_replace" name="/usr/lib/cups/backend/cups-pdf" pid=5135 comm="apparmor_parser"
Jun  3 10:36:35 acjcm3c kernel: [  532.132847] type=1400 audit(1307122594.994:320): apparmor="STATUS" operation="profile_replace" name="/usr/sbin/cupsd" pid=5135 comm="apparmor_parser"
Jun  3 10:36:35 acjcm3c init: cups main process (5136) terminated with status 127
Jun  3 10:36:35 acjcm3c init: cups main process ended, respawning

The solution:

It appears that Zend has put some of its libraries in the common dir which loads all the Zend related so's.

Just do these four commands:

cd /usr/local/zend/lib
sudo rm libldap_r-2.4.so.2
sudo rm libldap-2.4.so.2
sudo rm liblber-2.4.so.2