Common code in NuSOAP SOAP functions

NuSOAP (link in archive.org) is a library that allows you to quickly and easily create SOAP-based webservices in PHP. The problem that you may encounter, however, is the fact that there is no obvious way to put some common code that you want to run in all (or almost all) of your SOAP functions. Think eg. about connecting to a database, or checking some username and password (token) or doing some logging. I’ll explain in this post how you may achieve that. I was using NuSOAP 0.9.5.

Let’s start with some slightly modified PHP code from NuSOAP intro page (archive.org). Obviously, it is all about server-side, so we’ll be dealing with nusoap_server class.

<?php

// Pull in the NuSOAP code
require_once('lib/nusoap.php');
// Create the server instance
$server = new nusoap_server;
// Register the method to expose
$server->register('hello1');
$server->register('hello2');
$server->register('hello3');
// Define the methods as a PHP functions
function hello1() {
    return 'Hello1';
}
function hello2() {
    return 'Hello2';
}
function hello3() {
    return 'Hello3';
}
// Use the request to (try to) invoke the service
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);

OK, so we have three SOAP functions: hello1, hello2 and hello3. Nothing special. However, what to do if you want to run some common code on the beginning of all these three functions? Sure, you can put it in some another function (let’s call it ini_code()) and then just to call it from each function, ie. put ini_code(); after opening parenthesis of each function. The problem with this approach is twofold, however:

  • you will have to remember to add this line in each new SOAP function that you implement
  • you can’t return from SOAP function without checking for errors returned from ini_code which will make common code even bigger
  • it is ugly, unelegant and just simply lame (OK, this is a third reason).

The solution is to extend nusoap_server class and override its invoke_method method. If you open the file required in our example above (ie. lib/nusoap.php) you will notice that invoke_method is the place where your implemented SOAP functions are actually called from (near end of the method, via call_user_func_array or some more perverse methods if you are using PHP version without this function). So let’s create the file “nusoap_server_wrapper.php” and put the following code in it:

<?php
// see https://bartlomiejb.wordpress.com/2014/03/11/common-code-in-nusoap-soap-functions/

/*
 * We use this class to overwrite invoke_method() method
 * in order to put some common code in all of our implemented SOAP functions.
 */
class nusoap_server_wrapper extends nusoap_server {
    public function invoke_method() {
        // our common code here
        // you can use in it:
        // - $this->methodname - name of the called function
        // - $this->methodparams - parameters of the called function; it is an associative
        //   array with parameters' names as keys and actual values as array values
        // - $this->methodreturn - use it as an lvalue (ie. write to it) and then
        //   just |return;| to return from implemented SOAP function with a given value

        // as an example, let's write a called function name to a file
        $fp = fopen('nusoap-ext-test.txt', 'a'); // in production check for errors etc.
        fwrite($fp, 'called method is: ' . $this->methodname . "\n");
        fclose($fp);

        // invoke original NuSOAP code to handle our function
        parent::invoke_method();
    }
}

Read comments in this piece of code and all will be – hopefully – clear. You should now modify your server-side code to use this class instead of nusoap_server. So, assuming that “nusoap_server_wrapper.php” is in the same directory as our example from the top of the page, you would have to add require_once('nusoap_server_wrapper.php'); after require‘ing NuSOAP lib and then replace new nusoap_server with new nusoap_server_wrapper.

After running your client and calling all three SOAP functions you’ll notice not only that they work as usual, but that also their names are written to a file (obviously, you have to check write permissions etc. first) which proves that this code is indeed executed each time a SOAP function is called.

You should replace fopen/fwrite/fclose with your code, of course.

That’s it! We extended NuSOAP and run common code in an elegant and easily maintainable way.

Update (2014-12-09): added links to archive.org as it seems that NuSOAP page is gone.

Advertisements

rpm: How to list packages installed/upgraded today

If you’re using rpm-based Linux distro you may find this tip useful: if you want to list all packages installed or upgraded today (and by “today” I mean the current “today”, i.e. not hardcoded 2013/12/14, but the present time), just copy & paste the following snippet to the console window (this is ONE line!):

rpm -qa --qf '%{NAME} %{INSTALLTIME}\n' | perl -nale '($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($F[1]);($Nsec,$Nmin,$Nhour,$Nmday,$Nmon,$Nyear,$Nwday,$Nyday,$Nisdst)=localtime(time);print $F[0] if ($year==$Nyear && $mon==$Nmon && $mday==$Nmday)'

Here is how it works: we list all packages in a format “packagename installtime”. “installtime” is in a common Unix/Linux format: it is a number of seconds after a date called “epoch”. To convert it to something more readable/useful we can use perl and its function localtime, which converts it to an array of numbers of various meaning (like elements of the date: year, month, day, etc.). localtime(time) returns, on the other hand, the same data, but for the present time. So we just compare these two sets of values and if they match – we print the package name. Easy, isn’t it? 😉

Chroot 32-bit + Skype + PulseAudio = problems (solved!)

I recently was struggling a little bit with running Skype in my distro. The problem was that I had to configure chroot environment (because my native OS is 64-bit and Skype is a 32-bit application), and then also solve some problems with PulseAudio to get sound.

OK, so here are my findings and some useful shell scripts. First, we have to make sure that all important pieces of native system are also available in chrooted environment. Hence chroot_mount.sh script:

#!/bin/sh -x
CHROOTPATH="/mychroot"

cp -L /etc/resolv.conf $CHROOTPATH/etc/
mount --bind /dev $CHROOTPATH/dev
mount --bind /dev/pts $CHROOTPATH/dev/pts
mount --bind /dev/shm $CHROOTPATH/dev/shm
mount --bind /tmp $CHROOTPATH/tmp
mount -t proc proc $CHROOTPATH/proc
mount -t sysfs none $CHROOTPATH/sys
mount --bind /var/lib/dbus $CHROOTPATH/var/lib/dbus
mount --bind /var/run/dbus $CHROOTPATH/var/run/dbus
mount --bind /run/udev $CHROOTPATH/run/udev
mount --bind /home $CHROOTPATH/home

Run it from root. (Obviously, you have to create /mychroot dir earlier and install there base system. This part is out of scope of this blog post.)

After using your chrooted environment you may also want to umount all resources. Hence chroot_umount.sh script:

#!/bin/sh -x
CHROOTPATH="/mychroot"

umount $CHROOTPATH/dev/pts
umount $CHROOTPATH/dev/shm
umount $CHROOTPATH/dev
umount $CHROOTPATH/tmp
umount $CHROOTPATH/proc
umount $CHROOTPATH/sys
umount $CHROOTPATH/home
umount $CHROOTPATH/var/lib/dbus
umount $CHROOTPATH/var/run/dbus
umount $CHROOTPATH/run/udev

Then you have to configure PulseAudio so it can be used from different user than logged in (I prefer to run closed-source apps, like Skype, from a separate account.) Here is my ~/.pulse/default.pa file on main account:

.nofail
.fail
load-module module-device-restore
load-module module-stream-restore
load-module module-card-restore
load-module module-augment-properties
.ifexists module-udev-detect.so
load-module module-udev-detect
.else
load-module module-detect
.endif
.ifexists module-jackdbus-detect.so
.nofail
load-module module-jackdbus-detect
.fail
.endif
.ifexists module-bluetooth-discover.so
load-module module-bluetooth-discover
.endif
.ifexists module-esound-protocol-unix.so
load-module module-esound-protocol-unix
.endif
load-module module-native-protocol-unix
.ifexists module-gconf.so
.nofail
load-module module-gconf
.fail
.endif
load-module module-default-device-restore
load-module module-rescue-streams
load-module module-always-sink
load-module module-intended-roles
load-module module-suspend-on-idle
.ifexists module-console-kit.so
load-module module-console-kit
.endif
.ifexists module-systemd-login.so
load-module module-systemd-login
.endif
load-module module-position-event-sounds
load-module module-role-cork
load-module module-filter-heuristics
load-module module-filter-apply
.ifexists module-dbus-protocol.so
load-module module-dbus-protocol
.endif
load-module module-switch-on-port-available
load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1

On the secondary account I have only this in ~/.pulse/client.conf file:

default-server = 127.0.0.1

Also I have skype-wrapper.sh there in the PATH:

#!/bin/sh -x
export PULSE_SERVER=127.0.0.1
PULSE_LATENCY_MSEC=60 skype

Why it is needed? Well, without first line (export PULSE_SERVER=127.0.0.1) there was no sound and paplay always was saying Connection refused. Read PulseAudio’s FAQ about details how do the PulseAudio libraries decide where to connect to.

The second line (PULSE_LATENCY_MSEC=60 skype) was/is important to work around the bug in Skype that was adding some “funny” effects, like no sound at all or only some noises. Read this post from PulseAudio developer to learn more. I experienced these problems with PulseAudio 4.0 and Skype 4.2.0.11. This line works like a charm and all works OK.

OK, now when everything is configured (remember also to install and configure dchroot) you can run 32-bit Skype on a separate account by only running this command on your main account:
$ su -c 'dchroot -d skype-wrapper.sh' - user2
where “user2” is your secondary account.
You can make it an alias or put it in a one-line shell script to save some typing each time when you want to run Skype.

Translation of the “Reichskonkordat” article

I translated to Polish quite extensive “Reichskonkordat” article from the English Wikipedia, about concordat with Third Reich. It took me some time, but I was not in a hurry… Nice thing in Wikipedia is the fact that there are no deadlines ;-). When I started translating, the newest revision of the English article was this one and this is the base version of my translation in Polish-language Wikipedia.

Few days ago translated article was moved from my sandbox to the mainspace, i.e. article space. I also submitted article for display in the “Did you know” (“Czy wiesz” in Polish) section of the main page — its display is planned on December, 13th.

The newest version of the Polish article is here. (It may differ significantly from the version created by me.)

“Open with…” with multiple files

On Linux there is a standard related with desktop interactions and configuration. The standard describes, among other things, .desktop files. Important thing to remember when editing these files by hand (as I have done recently) is that when you want to pass multiple files as an argument to an app in “Exec” line, you have to give %F as an argument, like so:

Exec=coolapp %F

See The Exec key on standards.freedesktop.org.

First post!

OK, let’s see if this thing works at all… Sample PHP code follows – O(n) solution of equilibrium index problem (enable JavaScript from domains bartlomiejb.wordpress.com and wp.com [with subdomains] to see source code properly highlighted):

function solution( $A ) {
    $cnt = count( $A );
    if( $cnt == 0 )
        return -1;
    if( $cnt == 1 )
        return 0;
    
    $rsum = array_sum( $A );
    $lsum = 0;
    foreach( $A as $k => $v ) {
        $rsum -= $v;
        if( $lsum == $rsum )
            return $k;
        $lsum += $v;
    }
    return -1;
}

Documentation of this feature: http://en.support.wordpress.com/code/posting-source-code/