The core PHP libraries and the open source contributions to PHP provide innumerable functions. PHP extensions provide everything from byte-code caching to system calls. However, if you require specialized computation, you can create your own extension with the Simplified Wrapper and Interface Generator (SWIG).

Martin Streicher, Software Developer, Pixel, Byte, and Comma

author photo - martin streicherMartin Streicher is a freelance Ruby on Rails developer and the former Editor-in-Chief of Linux Magazine. Martin holds a Master of Science degree in computer science from Purdue University, and has programmed UNIX-like systems since 1986. He collects art and toys.


developerWorks Contributing author
        level

12 January 2010

Also available in Japanese Portuguese

Although writing a PHP extension isn't particularly onerous, SWIG simplifies the task further, largely by automating the work required to intertwine PHP and C or C++ code. Given a description of your function — its name and its formal arguments — SWIG generates a wrapper to bridge from PHP to low-level code.

SWIG has a few prerequisites. The most recent versions require PHP V5. You must also have a C/C++ compiler, such as the GNU Compiler Collection (GCC), and a copy of the PHP Module Development Kit (MDK). Specifically, you must have the header files associated with your PHP installation. If you use Ubuntu Linux® or a variation of Debian and you installed PHP V5 from a package repository, you can typically add the MDK using the Advanced Packaging Tool (APT). For example, on Ubuntu kernel 9.10, type apt-get install sudo apt-get install --install-recommends --yes php5-dev.

As of the end of 2009, the most recent release of SWIG is V1.3.40 (see Resources). Download the tarball (a gzip-compressed TAR file), unpack it, configure the code for your system, and build and install the software. (To find all the configuration options, run ./configure --help). Listing 1 provides the commands for downloading, unpacking, and installing SWIG.

Listing 1. Download, unpack, and install SWIG
$ wget http://prdownloads.sourceforge.net/swig/swig-1.3.40.tar.gz
$ tar xzf swig-1.3.40.tar.gz 
$ cd swig-1.3.40
$ ./configure 
$ make
$ sudo make install 
$ which swig
/usr/local/bin/swig

Building an extension

Let's build an extension to encrypt and decrypt messages with the Linux mcrypt library. PHP provides an mcrypt library, but it's little more than a very thin veneer over the library's C entry points. Here, let's build two far more succinct methods: one to encrypt a string and another to decrypt a string.

On Ubuntu and its analogs, you can install the pertinent mcrypt libraries and header files with APT: $ sudo apt-get install libmcrypt-dev libmcrypt4 mcrypt libmhash2.

If you prefer to build from scratch, or if your distribution does not include mcrypt, you can download the source code from its home page (see Resources). The mcrypt utility, which replaces crypt, also depends on libmhash, which you must build prior to compiling mcrypt. Listing 2 shows the code for building libmhash.

Listing 2. Building libmhash
$ # libmhash
$ wget http://sourceforge.net/projects/mhash/files/mhash/0.9.9.9/\
  mhash-0.9.9.9.tar.bz2/download
$ tar xfj mhash-0.9.9.9.tar.bz2
$ cd mhash-0.9.9.9
$ ./configure
$ make
$ sudo make install 

# libmcrypt
$ wget ftp://mcrypt.hellug.gr/pub/crypto/mcrypt/libmcrypt/\
  libmcrypt-2.5.7.tar.gz
$ tar xfz libmcrypt-2.5.7.tar.gz
$ cd libmcrypt-2.5.7
$ ./configure
$ make
$ sudo make install

$ # mcrypt
$ wget wget http://sourceforge.net/projects/mcrypt/files/MCrypt/2.6.8/\
  mcrypt-2.6.8.tar.gz/download
$ tar xfz mcrypt-2.6.8.tar.gz
$ cd mcrypt-2.6.8
$ ./configure
$ make
$ sudo make install

Next, create the C code for the extension. The interesting functions in the code are encode() and decode(), at the bottom of Listing 3. Both have two formal arguments — a string and a count — and both functions return a string. The former encrypts a plain-text string, returning its encoding; the latter decrypts an encoded string and returns plain text. Strings can be of any length.

The code uses the Data Encryption Standard-Electronic Codebook (DES-ECB) algorithm. The secret key can be any string of eight characters and is shown as 12345678 for demonstration purposes only. If you are exchanging encrypted messages with another party, obtain the party's key or create a new key and share it. (The encryption algorithm is architecture and language-independent. However, both the sender and the receiver must know the secret key.

Listing 3. The C code for the PHP extension
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mcrypt.h>

char *encode( char *string, int length );
char *decode( char *string, int length );

MCRYPT start() {
  MCRYPT td = mcrypt_module_open( "des", NULL, "ecb", NULL );
  if ( td == MCRYPT_FAILED ) {
    return( MCRYPT_FAILED );
  }

  if ( mcrypt_enc_self_test( td ) != 0 ) {
    return( MCRYPT_FAILED );
  }

  int i;
  char *IV;
  int iv_size = mcrypt_enc_get_iv_size( td );
  if ( iv_size != 0 ) {
    IV = calloc( 1, iv_size );
    for ( i = 0; i < iv_size; i++ ) {
      IV[ i ] = rand();
    }
  }

  int keysize = mcrypt_enc_get_key_size( td );
  char *key = calloc( 1, keysize );
  memcpy(key, "12345678", keysize);

  i = mcrypt_generic_init ( td, key, keysize, IV );
  if ( i < 0 ) {
    mcrypt_perror( i );
    exit(1);
  }

  return( td );
}


void end( MCRYPT td ) {
  mcrypt_generic_deinit( td );
  mcrypt_module_close( td );
}


#define B64_DEF_LINE_SIZE   72
#define B64_MIN_LINE_SIZE    4

/*
** encode 3 8-bit binary bytes as 4 '6-bit' characters
*/
void encodeblock( unsigned char in[3], unsigned char out[4], int len ) {
  static const char 
    cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  out[0] = cb64[ in[0] >> 2 ];
  out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
  out[2] = (unsigned char) (len > 1 ? cb64[ 
    ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
  out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
}


char *base64encode( char *input, int size ) {
  int i, x, len;
  unsigned char in[3], out[4];
  char *target = calloc( 1, ( ( size + 2 ) / 3 ) * 4 + 1 );
  char *t = target;

  for ( x = 0; x < size; ) {
    len = 0;

    for( i = 0; i < 3; i++ ) {
      if ( x < size ) {
        len++;
        in[i] = input[x++];
      }
      else {
        in[i] = 0;
      }
    }

    if( len ) {
      encodeblock( in, out, len );
      for( i = 0; i < 4; i++ ) {
        *t++ = out[i];
      }
    }
  }

  return( target );
}


char *encode( char *string, int length ) {
  MCRYPT td = start();
  int blocksize = mcrypt_enc_get_block_size( td );
  int cryptsize = ( ( length  + blocksize - 1 ) / blocksize ) * blocksize;
  char *target = calloc( 1,  cryptsize );

  memcpy( target, string, length );

  if ( mcrypt_generic( td, target, cryptsize ) != 0 ) {
    fprintf( stderr, "Code failing" );
  }

  end( td );

  char* result = base64encode( target, cryptsize );

  free( target );
  return result;
}


char *decode( char *string, int length ) {
  MCRYPT td = start();
  int blocksize = mcrypt_enc_get_block_size( td );
  char *block_buffer = calloc( 1, blocksize );
  int decryptlength = (length + blocksize - 1) / blocksize * blocksize;
  char *target = calloc( 1, decryptlength );

  memcpy(target, string, length);

  mdecrypt_generic( td, target, decryptlength );

  end( td );

  free(block_buffer);
  return( target );
}

Copy and paste the code in Listing 3 to a new file named secret.c. Your next task is to describe the API of the extension using SWIG's own syntax.


The SWIG file

At this point in development, you could handcraft an extension built upon secret.c. SWIG, though, does the hard work for you — with a minuscule amount of pseudo-code. Listing 4 shows secret.i, a SWIG template for the new extension.

Listing 4. secret.i
%module secret

%{
  extern char *encode( char *string, int length );
  extern char *decode( char *string, int length );
%}

extern char *encode( char *string, int length );
extern char *decode( char *string, int length );

A complete almanac of SWIG syntax and options is beyond the scope of this article. You can find complete documentation online (see Resources). Briefly, the SWIG file declares the name of the extension in line 1. The rest of the file declares the entry points. And that's it. Compilation requires a few steps: The first step generates the wrapper for your code: $ swig -php secret.i.

SWIG transforms secret.i to secret_wrap.c. The next few steps build and link the wrapper code, your extension, and the mcrypt library. Be sure to build each C source file with the -fpic option, which generates position-independent code suitable for a shared library.

$ cc -fpic -c secret.c
$ gcc `php-config --includes` -fpic -c secret_wrap.c
$ gcc -shared *.o -o secret.so -lmcrypt
$ sudo cp secret.so `php-config --extension-dir`

The first two commands build the C source. The third command builds the PHP extension. The -lmcrypt option resolves the calls in the extension with entry points in the mcrypt library. The fourth command places the new PHP extension in the proper directory so it can be loaded by PHP.

The final step before writing PHP code is to load the extension. Open the appropriate php.ini file — either for Apache or for the command-line variant of PHP — and add one line: extension=secret.so.

If you are unsure which php.ini file to edit, you can query PHP itself. Create this three-line program and run it using the browser or the interactive interpreter:

<?php
  phpinfo();
?>

Look for a line that begins Loaded Configuration File. For example, on the test platform used to create this article, the program generated the output Loaded Configuration File => /etc/php5/cli/php.ini. Hence, the file to edit is /etc/php5/cli/php.ini.


Writing the PHP code

With a shiny new extension in hand, you can now write PHP. Listing 5 shows code.php.

Listing 5. code.php
<?php
  include("secret.php");

  $string = "Double secret probation";
  $base64encode = secret::encode($string, strlen($string));
  $base64decode = base64_decode($base64encode);
  $decode = secret::decode( $base64decode, strlen($base64decode));

  echo $decode . "\n";
?>

Line 1 loads the extension. Line 4 encodes the string Double secret probation and uses Base64 to turn the encrypted string into printable characters that can easily be transmitted over e-mail, say. Line 5 unravels the Base64 encoding to yield raw characters, and line 6 decrypts the secret message to the original text.

Assuming that you save the code in coder.php and have installed the mcrypt library on your system in /usr/local/lib, you can run the example code with the PHP CLI command:

$ LD_LIBRARY_PATH=/usr/local/lib php ./code.php 
Double secret probation

Take a big SWIG

SWIG is a great way to reuse existing code. Wrap up your C or C++ libraries with SWIG, and integrate the result into your next Web or system application. Better yet, SWIG can generate wrappers for other scripting languages, too, from the exact same .i file. Write your extension once, and share it with PHP, Perl, Python, Ruby, and other developers.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=460607
ArticleTitle=Build PHP extensions with SWIG
publish-date=01122010