Avançar para a área de conteúdo

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

Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

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

  • Fechar [x]

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.

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

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

  • Fechar [x]

Criar extensões PHP com SWIG

Martin Streicher, Software Developer, Pixel, Byte, and Comma
author photo - martin streicher
Martin 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.

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

Data:  04/Mar/2010
Nível:  Intermediário
Atividade:  2251 visualizações
Comentários:  


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

Sobre o autor

author photo - martin streicher

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

Ajuda para Relatar Abuso

Relatar abuso

Obrigado. Esta entrada foi sinalizada para atenção do moderador.


Ajuda para Relatar Abuso

Relatar abuso

Falha no envio do Relatório de abuso. Tente novamente mais tarde.


developerWorks: Registre-se


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Selecione seu nome de exibição

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.

(Deve possuir de 3 a 31 caracteres.)


Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Classificar este artigo

Comentários

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
author1-email=martin.streicher@gmail.com
author1-email-cc=

Conheça a IBM da sua cidade

Virtual Branch Office Brasil

A IBM está mais perto do que você imagina!


Tags

Help
Use o campo de pesquisa para encontrar todos os tipos de conteúdo no My developerWorks com essa tag.

Use a barra de rolagem para ver mais ou menos tags.

Tags populares mostra as principais tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Minhas tags mostra suas tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Use o campo de pesquisa para localizar todos os tipos de conteúdo no Meu developerWorks com essa tag. Tags populares mostra as tags principais para essa zona de conteúdo particular (por exemplo, tecnologia Java, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere). Minhas tags mostra as suas tags para essa zona de conteúdo em particular (por exemplo, tecnologia Java, Linux, WebSphere).