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.

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.)

Przekład hasła “Reichskonkordat”

Przetłumaczyłem dosyć obszerne hasło “Reichskonkordat” z anglojęzycznej Wikipedii, o konkordacie z III Rzeszą. Trochę to trwało, ale się niespecjalnie spieszyłem… W Wikipedii lubię to, że nie ma deadline’ów ;-). Kiedy zaczynałem przekład, najnowszą wersją anglojęzycznego hasła była ta rewizja i na niej opiera się mój przekład w polskojęzycznej Wikipedii.

Kilka dni temu hasło trafiło z mojego brudnopisu do przestrzeni głównej, czyli artykułów. Zgłosiłem także hasło do ekspozycji w dziale “Czy wiesz…” na stronie głównej Wikipedii — jego ekspozycja jest zaplanowana na 13 grudnia br.

Jeśli kogoś interesuje europejska historia XX wieku, to zapraszam do lektury. (Najnowsza wersja hasła, mogąca się w przyszłości znacząco różnić od tej, którą dodałem, jest tutaj.)

Dla informacji: nie miałem dostępu do prac podanych jako bibliografia/przypisy. Zakładam, że nie ma żadnych przekłamań, ale w przyszłości dobrze by to było sprawdzić…

“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.

Lavabit zdechło, czyli Snowden i ja

W 2007 roku, szukając alternatywy dla GMaila (którego wolę unikać ze względu na to, że to usługa Google, a Google ma bardzo dużo danych o każdym i wolę im więcej nie udostępniać) natrafiłem na serwis Lavabit. Adres tego serwisu to https://lavabit.com/.

W 2007, kiedy zakładałem konto, serwis nazywał się jeszcze Nerdshack i w takiej domenie mam tam kilka skrzynek pocztowych.

Tworzę ten wpis m.in. jako podziękowanie dla tego serwisu za lata bezproblemowego działania. Serwis był (w podstawowej opcji) darmowy i nie przysyłał żadnych reklam na skrzynkę.

Od kilku dni nie mogłem się połączyć z serwerami Lavabit. Aktualnie na głównej stronie Lavabit znajduje się oświadczenie właściciela tego serwisu o mniej-więcej następującej treści (tłumaczenie za Niebezpiecznikiem):

Moi drodzy użytkownicy, zostałem zmuszony do podjęcia decyzji; albo zostanę uznany za współwinnego zbrodniom przeciw narodowi amerykańskiemu, albo spiszę na straty 10 lat ciężkiej pracy i wyłączę Lavabit. Po głębokim namyśle, zdecydowałem zawiesić działanie serwisu. Chciałbym móc w zgodzie z prawem podzielić się z wami opisem wydarzeń, które doprowadziły mnie do tej decyzji. Ale nie mogę. Zasługujecie aby wiedzieć co się stało, a ja na mocy pierwszej poprawki powinienem mieć gwarancję wolności wypowiedzi w tego typu sytuacjach, ale niestety Kongres przeforsował ustawę, która twierdzi inaczej. Na chwilę obecną nie mogę opisać wam tego co działo się przez 6 ostatnich tygodni, pomimo moich dwukrotnych próśb (o zgodę).

Co teraz się stanie? Już przygotowuję odwołanie do sądu. Pomyślna jego decyzja pozwoli mi wskrzesić Lavabit jako amerykańską firmę.

Te wydarzenia nauczyły mnie jednej lekcji: mocno odradzam wszystkim powierzanie swoich prywatnych danych firmom mającym amerykańskie korzenie.

Ladar Levison

Właściciel Lavabit

Warto też dodać, że pod tym tekstem znajduje się jeszcze prośba o pomoc finansową:

Obrona konstytucji jest kosztowna! Pomóż nam, wpłacając pieniądze na Fundusz Obrony Prawnej Lavabitu tutaj.

Decyzja o zamknięciu spowodowała falę komentarzy w Internecie, m.in. na Slashdocie, w Guardianie (który zajmuje się od początku tematem rewelacji Snowdena, bo Snowden skontaktował się z dziennikarzem Guardiana właśnie) i w innych miejscach.

Wg serwisu Globalpost (który powołuje się na obrończynię praw człowieka Tanię Lokszinę), Snowden użył adresu “edsnowden@lavabit.com”, żeby poinformować wybrane osoby o konferencji, którą zwołał 12 lipca br. przebywając na lotnisku w Moskwie.

Wg niektórych spekulacji sytuacja może wyglądać zatem tak:

  • amerykańskie władze chciały się koniecznie dobrać do danych dotyczących Snowdena na tej skrzynce
  • jak można było przeczytać na stronach Lavabitu, płacący użytkownicy tego serwisu mieli opcję dodatkowej ochrony swoich danych: ich poczta była szyfrowana po stronie serwera, tak więc nawet właściciel serwisu nie mógł przeczytać ich wiadomości (dlaczego inni providerzy poczty tak standardowo nie robią?!), chyba że znał hasło
  • amerykańskie władze poleciły zatem zbieranie haseł (albo tylko hasła Snowdena), na co właściciel Lavabitu nie chciał się zgodzić
  • o niektórych żądaniach amerykańskich władz nie można nawet publicznie mówić, bo grożą za to sankcje
  • ponieważ właściciel Lavabitu nie chciał się zgodzić na takie działania, zamknął serwis całkowicie, co uniemożliwia zebranie haseł (hasła) i tym samym ochronę danych swoich użytkowników.

Moim zdaniem jest to bardzo odważne i słuszne działanie ze strony właściciela Lavabitu. Mam nadzieję, że serwis wróci jeszcze kiedyś do życia.

UPDATE (2017-07-01): serwis ponownie działa, ponoć od stycznia 2017. Mam z powrotem dostęp do kont, do których miałem wcześniej. Good job, Lavabit!

Jak usunąć ogonki z polskich znaków używając perla

Edycja (2013-08-11): dodałem info o Windows.

Edycja (2013-09-28): dodałem info o konwersji pliku w UTF8 na Windows.

Zakładam, że używamy Linuksa na terminalu obsługującym UTF8. Testowane na perlu 5.18.0.

Nasz plik (polskie znaki w UTF8):

$ cat tmp.txt
ęóąśłźżćń ĘÓĄŚŁŹŻĆŃ
ĘÓĄŚŁŹŻĆŃ ęóąśłźżćń
W Strzebrzeszynie chrząszcz brzmi w trzcinie i Strzebrzeszyn z tego słynie.
Zażółć gęślą jaźń.

Jednolinijkowiec w perlu:

$ cat tmp.txt | perl -Mutf8 -MEncode -wple '$_=decode("utf8",$_);tr/ęóąśłźżćńĘÓĄŚŁŹŻĆŃ/eoaslzzcnEOASLZZCN/'
eoaslzzcn EOASLZZCN
EOASLZZCN eoaslzzcn
W Strzebrzeszynie chrzaszcz brzmi w trzcinie i Strzebrzeszyn z tego slynie.
Zazolc gesla jazn.

W Windows (XP PL; Activestate Perl 5.8.9) wystarczy (plik tmp.txt kodowany w lokalnym standardzie CP1250):

type tmp.txt | perl -wple "tr/ęóąśłźżćńĘÓĄŚŁŹŻĆŃ/eoaslzzcnEOASLZZCN/"

Okazuje się, że polskie znaki w wierszu poleceń Windows są w którymś miejscu niejawnie konwertowane do CP1250 (mimo że normalnie na konsoli obowiązuje CP852).

Konwersja pliku zapisanego w UTF8 (Notatnik umożliwia zapis w tym kodowaniu; dodaje wtedy też BOM na początku, więc trzeba go usunąć) wymaga nieco więcej zachodu…:

type tmp.txt | perl -MEncode=decode -wple "BEGIN { $pl='ęóąśłżźćńĘÓĄŚŁŻŹĆŃ';$pl=decode('CP1250', $pl); $bom = join'',map(chr,(0xef,0xbb,0xbf))} s/^$bom//; $_=decode('UTF8', $_); eval 'tr/' . $pl . '/eoaslzzcnEOASLZZCN/'"

eval pod koniec jest niezbędne, bo operator “tr” nie obsługuje normalnie zmiennych w listach do zamiany.
Testowane z ActiveState perlem 5.10.1 na Windows 7 Starter PL SP1 oraz ActiveState perlem 5.12.4 na Windows XP PL SP3.

Jak dodać zdjęcie do Wikipedii/Commons – filmy

W odpowiedzi na ogólnie skierowaną prośbę Adama Kliczka na liście wikipl-l nagrałem filmy opisujące procedurę ładowania zdjęć do Wikimedia Commons i wrzuciłem na swoje konto na Dailymotion. Filmy osadzone są poniżej.

Część 1 – uwagi wstępne o Commons oraz zakładanie konta:

Część 2 – ładowanie zdjęcia na Commons, dodawanie tytułu, opisu itd.:

Część 3 – logowanie się na Commons, odnalezienie swoich
załadowanych plików, edytowanie strony opisu na Commons
załadowanego pliku – usunięcie (dodanie) szablonu,
odnalezienie właściwej kategorii i jej dodanie do zdjęcia,
wykorzystanie zdjęcia w Wikipedii:

Dla najlepszego efektu najlepiej wybrać opcję odtwarzania na pełnym ekranie i wybrać rozdzielczość HD (720).