As bibliotecas PHP principais e as contribuições de software livre para PHP oferecem inúmeras funções. As extensões PHP oferecem tudo, desde cache de código de bytes até chamadas de sistema. Entretanto, se precisar de computação especializada, você poderá criar sua própria extensão com o Simplified Wrapper and Interface Generator (SWIG).

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

author photo - martin streicherMartin Streicher é desenvolvedor autônomo de Ruby on Rails e o editor-chefe anterior da Linux Magazine. Martin é Mestre em Ciência da Computação pela Purdue University e faz programação de sistemas do tipo UNIX desde 1986. Ele coleciona arte e brinquedos.


nível de autor Contribuidor do
        developerWorks

04/Mar/2010

Embora a gravação em uma extensão PHP não seja particularmente onerosa, SWIG simplificará mais a tarefa, muito pela automatização do trabalho necessário para unir PHP e o código C ou C++. Com uma descrição da função apresentada — seu nome e seus argumentos formais — SWIG gera um wrapper para formar uma ponte entre PHP e o código de baixo nível.

SWIG tem alguns pré-requisitos. As versões mais recentes solicitam PHP V5. É preciso também ter um compilador C/C++, como o GNU Compiler Collection (GCC), e uma cópia do Module Development Kit (MDK) para PHP. Especificamente, é preciso ter os arquivos de cabeçalho associados à sua instalação de PHP. Caso utilize Ubuntu Linux® ou uma variação de Debian e instale PHP V5 a partir de um repositório de pacote, você poderá geralmente adicionar o MDK usando Advanced Packaging Tool (APT). Por exemplo, no kernel Ubuntu 9.10, digite apt-get install sudo apt-get install --install-recommends --yes php5-dev.

No fim de 2009, a release mais recente de SWIG era a V1.3.40 (consulte Recursos). Faça o download de tarball (um arquivo TAR compactado por gzip), descompacte-o, configure o código do sistema e crie e instale o software. (Para encontrar todas as opções de configuração, execute ./configure --help). A Listagem 1 apresenta os comandos para download, descompactação e instalação de SWIG.

Listagem 1. Download, descompactação e instalação de 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

Criando uma extensão

Vamos criar uma extensão para criptografar e decriptografar mensagens com a biblioteca mcrypt do Linux. PHP oferece uma biblioteca mcrypt, mas ela é um pouco mais do que um aglomerado muito fino sobre os pontos de entrada de C da biblioteca. Aqui, vamos criar dois métodos bem mais sucintos: um para criptografar uma cadeia de caracteres e outro para decriptografá-la.

Em Ubuntu e seus semelhantes, é possível instalar as bibliotecas mcrypt pertinentes e os arquivos de cabeçalho com APT: $ sudo apt-get install libmcrypt-dev libmcrypt4 mcrypt libmhash2.

Se preferir criar do zero ou se a sua distribuição não tiver mcrypt, você poderá fazer o download do código de origem de sua página inicial (consulte Recursos). O utilitário mcrypt, que substitui crypt, também depende de libmhash, que deve ser criado antes da compilação de mcrypt. A Listagem 2 mostra o código para a criação de libmhash.

Listagem 2. Criando 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

Em seguida, crie o código C para a extensão. As funções interessantes no código são encode() e decode(), na parte inferior da Listagem 3. Ambas têm dois argumentos formais — uma cadeia de caracteres e uma contagem — e as duas funções retornam uma cadeia de caracteres. A primeira criptografa uma cadeia de caracteres com texto simples, retornando sua codificação; a última decriptografa uma cadeia de caracteres codificada e retorna texto simples. As cadeias de caracteres podem ter qualquer extensão.

O código usa o algoritmo Data Encryption Standard-Electronic Codebook (DES-ECB). A chave secreta pode ser qualquer cadeia de caracteres de oito caracteres e é mostrada como 12345678 somente para fins de demonstração. Se estiver trocando mensagens criptografadas com outra parte, obtenha a chave da parte ou crie uma nova chave e a compartilhe. (O algoritmo de criptografia é independente de arquitetura e linguagem.) Entretanto, tanto o remetente quanto o destinatário devem saber a chave secreta.

Listagem 3. O código C para a extensão PHP
#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 );
}

Copie e cole o código da Listagem 3 em um novo arquivo denominado secret.c. Sua próxima tarefa é descrever a API da extensão usando a própria sintaxe de SWIG.


O arquivo SWIG

Neste ponto do desenvolvimento, é possível criar manualmente uma extensão com base em secret.c. SWIG, entretanto, faz o trabalho pesado para você — com uma quantidade minúscula de pseudocódigo. A Listagem 4 mostra secret.i, um modelo de SWIG para a nova extensão.

Listagem 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 );

Um almanaque completo de sintaxe e opções de SWIG vai além do escopo deste artigo. É possível encontrar documentação completa on-line (consulte Recursos). Resumidamente, o arquivo SWIG declara o nome da extensão na linha 1. O restante do arquivo declara os pontos de entrada. É isso. A compilação requer poucas etapas: a primeira etapa gera o wrapper para o seu código: $ swig -php secret.i.

SWIG transforma secret.i em secret_wrap.c. As próximas etapas criam e vinculam o código do wrapper, sua extensão e a biblioteca mcrypt. Certifique-se de criar cada arquivo de origem C com a opção -fpic, que gera código independente de posição adequado para uma biblioteca compartilhada.

$ 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`

Os dois primeiros comandos criam a origem C. O terceiro comando cria a extensão PHP. A opção -lmcrypt determina as chamadas na extensão com pontos de entrada na biblioteca mcrypt. O quarto comando coloca a nova extensão PHP no diretório correto para que ela possa ser carregada por PHP.

A etapa final antes de escrever o código PHP é carregar a extensão. Abra o arquivo php.ini apropriado — para Apache ou para a variante de linha de comando de PHP — e adicione uma linha: extension=secret.so.

Se não tiver certeza de qual arquivo php.ini editar, você poderá consultar o próprio PHP. Crie esse programa de três linhas e o execute usando o navegador ou o interpretador interativo:

<?php
  phpinfo();
?>

Procure uma linha que começa com Loaded Configuration File. Por exemplo, na plataforma de teste usada para criar este artigo, o programa gerou a saída Loaded Configuration File => /etc/php5/cli/php.ini. Consequentemente, o arquivo a ser editado é /etc/php5/cli/php.ini.


Escrevendo o código PHP

Com uma nova extensão brilhante em mãos, agora é possível escrever PHP. A Listagem 5 mostra code.php.

Listagem 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";
?>

A linha 1 carrega a extensão. A linha 4 codifica a cadeia de caracteres Double secret probation e usa Base64 para transformar a cadeia de caracteres criptografada em caracteres imprimíveis que podem ser transmitidos facilmente por e-mail, digamos. A linha 5 mostra a codificação Base64 para gerar caracteres brutos, e a linha 6 decriptografa uma mensagem secreta para o texto original.

Considerando que você salve o código em coder.php e tem instalado a biblioteca mcrypt no seu sistema em /usr/local/lib, é possível executar o código de exemplo com o comando PHP CLI:

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

Usar um SWIG grande

SWIG é uma excelente forma de reutilizar o código existente. Finalize suas bibliotecas C ou C++ com SWIG e integre o resultado ao seu próximo aplicativo de sistema ou Web. Melhor ainda, SWIG pode gerar wrappers para outras linguagens de script também, exatamente do mesmo arquivo .i. Escreva sua extensão apenas uma vez e a compartilhe com PHP, Perl, Python, Ruby e outros desenvolvedores.

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre
ArticleID=471520
ArticleTitle=Criar extensões PHP com SWIG
publish-date=03042010