Criando extensão para php
Posted by Mathias Grimm on dezembro 31, 2008 in C/C++, Linux, PHP
Boa noite a todos!
Resolvi estudar um pouco a criação de extensões do php, e publicar um "hello Wolrd" para vcs.
Achei um pouco complexo para um simples hello world mas no final acabei me acostumando.
Bom, desenvolvi a extensão num ubuntu 8.10 server e um php 5.2.8.
Vamos ao que interessa...
Primeiro você precisa baixar o código fonte do php, baixe a versão tar.bz2 pois é menor por ter uma compactação mais otimizada, mas se quiser baixar a versão .tar.gz da na mesma, só que demora mais pra baixar. Agora descompacte usando tar xvjf php-5.2.8.tar.bz2. Esse nome pode variar de acordo com a versão baixada. Também será necessário conhecimento em C pois o código fonte do php é em C.
Agora entre na pasta digitando cd php-5.2.8. Dentro da pasta existem varios arquivos (mais de 10 mil eu acho) subdivididos em algumas pastas. As extensões ficam na pasta php-5.2.8/ext/ que é onde vc criará a sua! Pronto! Agora vamos criar o arquivo de definição da sua função. Crie dentro da pasta ext um arquivo chamado mg_teste.def (mg_teste sera o nome da extensão) e dentro dele coloque o seguinte texto: string hello_world(string name) e salve o arquivo. Esse arquivo é utilizado para o php gerar um template para seu plugin.
Agora dentro da pasta ext digite o seguinte comando (como root, ou com sudo) ./ext_skel --extname=mg_teste --proto=mg_teste.def . Tal comando gera a estrutura de diretórios e os arquivos template dentro desses diretórios.
Nossa extensão se chamará mg_teste, então após o comando ./ext_skel anterior será gerado a pasta mg_teste dentro de ext
Após o ext_skel é mostrado um texto mandando executar os seguintes comandos:
cd .. vi ext/mg_teste/config.m4 ./buildconf ./configure --[with|enable]-mg_teste make ./php -f ext/mg_teste/mg_teste.php vi ext/mg_teste/mg_teste.c make
Bom, vou passo a passo:
o cd.. eh para vc "cair" na pasta php-5.2.8
o vi ext/mg_teste/config.m4 é um dos arquivos gerados... nele vc deve descomentar 2 linhas para que o plugin funcione.
Descomente as linhas PHP_ARG_ENABLE(mg_teste, whether to enable mg_teste support,
e [ --enable-mg_teste Enable mg_teste support])
Aqui estavam na linha 16 e 18 mas talvez não seja o seu caso.
Agora o comando ./buildconf só funcionou com a opção --force, ficando ./buildconf --force
O comando ./configure --enable-mg_teste deve ser usado para verificar as depenências e também habilitar a extensão que estamos criando.. provavelmente nesse momento vc tera alguns problemas. Eu tive que instalar o pacote libxml2-dev pois estava faltando. Instalei utilizando apt-get install libxml2-dev
O make também tive que instalar. apt-get install make
O make é que compila todo o php juntamente com sua extensão. A compilação demorou um pouco aqui... uns 5 minutos eu acho, ou mais.
O comando ./php -f ext/mg_teste/mg_teste.php não funcionou aqui pois o executavel do php foi salvo em /home/mathias/php-5.2.8/sapi/cli/php então tive que rodar com /home/mathias/php-5.8.2/sapi/cli/php -f /home/mathias/php-5.2.8/ext/mg_teste/mg_teste.php
O Comando vi ext/mg_teste/mg_teste.c é sugerido para que vc implemente sua função, caso contrário ela conterá um código que só emite um erro falando que ela ainda não foi implementada.Foi aí que implementei o hello world.
Sempre que você alterar o mg_teste.c deve executar o make para compilar. Sempre execute o make na raiz do php, ou seja , em /home/mathias/php-5.2.8/ . Essa compilação foi mais rápida, leva uns 20 segundos eu acho.
É isso... esse são os passos para criar a extensão. Pra testar criei um arquivo teste.php dentro de /home/mathias
<?php ?>
Para executa-lo usei o comando /home/mathias/php-5.2.8/sapi/cli/php -f /home/mathias/teste.php
Segue o código do mg_teste.c:
/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: | +----------------------------------------------------------------------+ */ /* $Id: header,v 1.16.2.1.2.1 2007/01/01 19:32:09 iliaa Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_mg_teste.h" /* If you declare any globals in php_mg_teste.h uncomment this: ZEND_DECLARE_MODULE_GLOBALS(mg_teste) */ /* True global resources - no need for thread safety here */ static int le_mg_teste; /* {{{ mg_teste_functions[] * * Every user visible function must have an entry in mg_teste_functions[]. */ zend_function_entry mg_teste_functions[] = { PHP_FE(confirm_mg_teste_compiled, NULL) /* For testing, remove later. */ PHP_FE(hello_world, NULL) {NULL, NULL, NULL} /* Must be the last line in mg_teste_functions[] */ }; /* }}} */ /* {{{ mg_teste_module_entry */ zend_module_entry mg_teste_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif "mg_teste", mg_teste_functions, PHP_MINIT(mg_teste), PHP_MSHUTDOWN(mg_teste), PHP_RINIT(mg_teste), /* Replace with NULL if there's nothing to do at request start */ PHP_RSHUTDOWN(mg_teste), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(mg_teste), #if ZEND_MODULE_API_NO >= 20010901 "0.1", /* Replace with version number for your extension */ #endif STANDARD_MODULE_PROPERTIES }; /* }}} */ #ifdef COMPILE_DL_MG_TESTE ZEND_GET_MODULE(mg_teste) #endif /* {{{ PHP_INI */ /* Remove comments and fill if you need to have entries in php.ini PHP_INI_BEGIN() STD_PHP_INI_ENTRY("mg_teste.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_mg_teste_globals, mg_teste_globals) STD_PHP_INI_ENTRY("mg_teste.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_mg_teste_globals, mg_teste_globals) PHP_INI_END() */ /* }}} */ /* {{{ php_mg_teste_init_globals */ /* Uncomment this function if you have INI entries static void php_mg_teste_init_globals(zend_mg_teste_globals *mg_teste_globals) { mg_teste_globals->global_value = 0; mg_teste_globals->global_string = NULL; } */ /* }}} */ /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(mg_teste) { /* If you have INI entries, uncomment these lines REGISTER_INI_ENTRIES(); */ return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(mg_teste) { /* uncomment this line if you have INI entries UNREGISTER_INI_ENTRIES(); */ return SUCCESS; } /* }}} */ /* Remove if there's nothing to do at request start */ /* {{{ PHP_RINIT_FUNCTION */ PHP_RINIT_FUNCTION(mg_teste) { return SUCCESS; } /* }}} */ /* Remove if there's nothing to do at request end */ /* {{{ PHP_RSHUTDOWN_FUNCTION */ PHP_RSHUTDOWN_FUNCTION(mg_teste) { return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(mg_teste) { php_info_print_table_start(); php_info_print_table_header(2, "mg_teste support", "enabled"); php_info_print_table_end(); /* Remove comments if you have entries in php.ini DISPLAY_INI_ENTRIES(); */ } /* }}} */ /* Remove the following function when you have succesfully modified config.m4 so that your module can be compiled into PHP, it exists only for testing purposes. */ /* Every user-visible function in PHP should document itself in the source */ /* {{{ proto string confirm_mg_teste_compiled(string arg) Return a string to confirm that the module is compiled in */ PHP_FUNCTION(confirm_mg_teste_compiled) { char *arg = NULL; int arg_len, len; char *strg; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { return; } len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "mg_teste", arg); RETURN_STRINGL(strg, len, 0); } /* }}} */ /* The previous line is meant for vim and emacs, so it can correctly fold and unfold functions in source code. See the corresponding marks just before function definition, where the functions purpose is also documented. Please follow this convention for the convenience of others editing your code. */ /* {{{ proto string hello_world(string name) */ PHP_FUNCTION(hello_world) { char *name = NULL; int argc = ZEND_NUM_ARGS(); int name_len = 0; if (zend_parse_parameters(argc TSRMLS_CC, "s", &name, &name_len) == FAILURE) { return; } RETURN_STRING(name, 1); } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */
Vc deverá editar a função PHP_FUNCTION(hello_world) localizada na linha 176
Agora é só brincar...
Todo esse código foi gerado automaticamente pelo ext_skel e para entende-lo precisaremos entender as macros que já foram criadas pelo pessoal do php.
Verifique agora que sua extensão aparece no php.ini digitando /home/mathias/php-5.2.8/sapi/cli/php -r 'phpinfo();' |grep -i mg_teste .

Para baixar os arquivo utilizados clique aqui!
Descompatece os arquivos dentro da pasta ext.
Agradeço a presença de todos e voltem sempre!
5 Comentários on Criando extensão para php
By Cristiano Teles on janeiro 2, 2009 at 11:02 am
Muito interessante essa funcionalidade, porem poderia ter dado um exemplo mais completo, como por exemplo como gerar o balancete, rs.
Agora falando sério, será que teríamos ganho de performance considerável criando uma extensão para trabalhar com massa de dados texto?
By CesarDraw on janeiro 2, 2009 at 11:39 am
Muito maneiro Mr. Grimm!
Mas me diga uma coisa… essa parada aê só rola de colocar uma única função?
Ou seja p/ cada nova função terei que criar uma nova extenção?
tipo se eu quisesse ter: dentro da extensão HelloWorld mais de uma função rola de boas?
By Mathias Grimm on janeiro 2, 2009 at 1:01 pm
Cristiano,não tenho a resposta para isso, mas vou fazer uns testes e coloco aqui no blog assim que possível. Acredito que fique mais rapido, mas vou testar de qualquer maneira.
Como seria a manipulação dessa massa de dados? Importar um txt direto pro banco? Algo do tipo?
Mr. Draw, vc pode criar N funções dentro do mg_teste.c. Ou seja, criar todas funções da sua extensão.
By Marcio Muzzi on janeiro 16, 2009 at 2:27 pm
Boa Mathias. Acredito que todo mundo já pensou em parar pra fazer uma função para o PHP, seja algo que não existe (o que é raro já que o PHP tem função de rodo), seja para escrever uma função equivalente onde a nativa do PHP não faz bem o que a gente precisa.
Ficou em aberto apenas você comentar como tratar a questão da portabilidade do sistema e a compatibilidade com futuras versões.
if (!function_exists(’minha_func’))
{ throw new Exception(’ops, esqueci de compilar a minha_func no novo servidor…’); }
[]s
By Helder.mauricio on março 2, 2009 at 12:09 pm
Eu utilizei um tutorial um pouco diferente e mais completo veja aqui http://www.hudzilla.org/php/20_6_0.php ai eu tentei fazer um php-glut mas ele complila mas não linca com a biblioteca original libglut.a ou libglut.so
Alguem saberia como faço para lincar
Subscribe
Follow comments by subscribing to the Criando extensão para php Comments RSS feed.