BuscaPé, líder em comparação de preços na América Latina

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,
[  --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

  1. <?php
  2. echo hello_world("Mathias Grimm");
  3. ?>

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:

  1. /*
  2.   +----------------------------------------------------------------------+
  3.   | PHP Version 5 |
  4.   +----------------------------------------------------------------------+
  5.   | Copyright (c) 1997-2007 The PHP Group |
  6.   +----------------------------------------------------------------------+
  7.   | This source file is subject to version 3.01 of the PHP license, |
  8.   | that is bundled with this package in the file LICENSE, and is |
  9.   | available through the world-wide-web at the following url: |
  10.   | http://www.php.net/license/3_01.txt |
  11.   | If you did not receive a copy of the PHP license and are unable to |
  12.   | obtain it through the world-wide-web, please send a note to |
  13.   | license@php.net so we can mail you a copy immediately. |
  14.   +----------------------------------------------------------------------+
  15.   | Author: |
  16.   +----------------------------------------------------------------------+
  17. */
  18.  
  19. /* $Id: header,v 1.16.2.1.2.1 2007/01/01 19:32:09 iliaa Exp $ */
  20.  
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24.  
  25. #include "php.h"
  26. #include "php_ini.h"
  27. #include "ext/standard/info.h"
  28. #include "php_mg_teste.h"
  29.  
  30. /* If you declare any globals in php_mg_teste.h uncomment this:
  31. ZEND_DECLARE_MODULE_GLOBALS(mg_teste)
  32. */
  33.  
  34. /* True global resources - no need for thread safety here */
  35. static int le_mg_teste;
  36.  
  37. /* {{{ mg_teste_functions[]
  38.  *
  39.  * Every user visible function must have an entry in mg_teste_functions[].
  40.  */
  41. zend_function_entry mg_teste_functions[] = {
  42. PHP_FE(confirm_mg_teste_compiled, NULL) /* For testing, remove later. */
  43. PHP_FE(hello_world, NULL)
  44. {NULL, NULL, NULL} /* Must be the last line in mg_teste_functions[] */
  45. };
  46. /* }}} */
  47.  
  48. /* {{{ mg_teste_module_entry
  49.  */
  50. zend_module_entry mg_teste_module_entry = {
  51. #if ZEND_MODULE_API_NO >= 20010901
  52. STANDARD_MODULE_HEADER,
  53. #endif
  54. "mg_teste",
  55. mg_teste_functions,
  56. PHP_MINIT(mg_teste),
  57. PHP_MSHUTDOWN(mg_teste),
  58. PHP_RINIT(mg_teste), /* Replace with NULL if there's nothing to do at request start */
  59. PHP_RSHUTDOWN(mg_teste), /* Replace with NULL if there's nothing to do at request end */
  60. PHP_MINFO(mg_teste),
  61. #if ZEND_MODULE_API_NO >= 20010901
  62. "0.1", /* Replace with version number for your extension */
  63. #endif
  64. STANDARD_MODULE_PROPERTIES
  65. };
  66. /* }}} */
  67.  
  68. #ifdef COMPILE_DL_MG_TESTE
  69. ZEND_GET_MODULE(mg_teste)
  70. #endif
  71.  
  72. /* {{{ PHP_INI
  73.  */
  74. /* Remove comments and fill if you need to have entries in php.ini
  75. PHP_INI_BEGIN()
  76.   STD_PHP_INI_ENTRY("mg_teste.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_mg_teste_globals, mg_teste_globals)
  77.   STD_PHP_INI_ENTRY("mg_teste.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_mg_teste_globals, mg_teste_globals)
  78. PHP_INI_END()
  79. */
  80. /* }}} */
  81.  
  82. /* {{{ php_mg_teste_init_globals
  83.  */
  84. /* Uncomment this function if you have INI entries
  85. static void php_mg_teste_init_globals(zend_mg_teste_globals *mg_teste_globals)
  86. {
  87. mg_teste_globals->global_value = 0;
  88. mg_teste_globals->global_string = NULL;
  89. }
  90. */
  91. /* }}} */
  92.  
  93. /* {{{ PHP_MINIT_FUNCTION
  94.  */
  95. PHP_MINIT_FUNCTION(mg_teste)
  96. {
  97. /* If you have INI entries, uncomment these lines
  98. REGISTER_INI_ENTRIES();
  99. */
  100. return SUCCESS;
  101. }
  102. /* }}} */
  103.  
  104. /* {{{ PHP_MSHUTDOWN_FUNCTION
  105.  */
  106. PHP_MSHUTDOWN_FUNCTION(mg_teste)
  107. {
  108. /* uncomment this line if you have INI entries
  109. UNREGISTER_INI_ENTRIES();
  110. */
  111. return SUCCESS;
  112. }
  113. /* }}} */
  114.  
  115. /* Remove if there's nothing to do at request start */
  116. /* {{{ PHP_RINIT_FUNCTION
  117.  */
  118. PHP_RINIT_FUNCTION(mg_teste)
  119. {
  120. return SUCCESS;
  121. }
  122. /* }}} */
  123.  
  124. /* Remove if there's nothing to do at request end */
  125. /* {{{ PHP_RSHUTDOWN_FUNCTION
  126.  */
  127. PHP_RSHUTDOWN_FUNCTION(mg_teste)
  128. {
  129. return SUCCESS;
  130. }
  131. /* }}} */
  132.  
  133. /* {{{ PHP_MINFO_FUNCTION
  134.  */
  135. PHP_MINFO_FUNCTION(mg_teste)
  136. {
  137. php_info_print_table_start();
  138. php_info_print_table_header(2, "mg_teste support", "enabled");
  139. php_info_print_table_end();
  140.  
  141. /* Remove comments if you have entries in php.ini
  142. DISPLAY_INI_ENTRIES();
  143. */
  144. }
  145. /* }}} */
  146.  
  147. /* Remove the following function when you have succesfully modified config.m4
  148.   so that your module can be compiled into PHP, it exists only for testing
  149.   purposes. */
  150.  
  151. /* Every user-visible function in PHP should document itself in the source */
  152. /* {{{ proto string confirm_mg_teste_compiled(string arg)
  153.   Return a string to confirm that the module is compiled in */
  154. PHP_FUNCTION(confirm_mg_teste_compiled)
  155. {
  156. char *arg = NULL;
  157. int arg_len, len;
  158. char *strg;
  159.  
  160. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
  161. return;
  162. }
  163.  
  164. len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "mg_teste", arg);
  165. RETURN_STRINGL(strg, len, 0);
  166. }
  167. /* }}} */
  168. /* The previous line is meant for vim and emacs, so it can correctly fold and
  169.   unfold functions in source code. See the corresponding marks just before
  170.   function definition, where the functions purpose is also documented. Please
  171.   follow this convention for the convenience of others editing your code.
  172. */
  173.  
  174. /* {{{ proto string hello_world(string name)
  175.   */
  176. PHP_FUNCTION(hello_world)
  177. {
  178. char *name = NULL;
  179. int argc = ZEND_NUM_ARGS();
  180. int name_len = 0;
  181.  
  182. if (zend_parse_parameters(argc TSRMLS_CC, "s", &name, &name_len) == FAILURE)
  183. {
  184. return;
  185. }
  186.  
  187. RETURN_STRING(name, 1);
  188. }
  189. /* }}} */
  190.  
  191. /*
  192.  * Local variables:
  193.  * tab-width: 4
  194.  * c-basic-offset: 4
  195.  * End:
  196.  * vim600: noet sw=4 ts=4 fdm=marker
  197.  * vim<600: noet sw=4 ts=4
  198.  */

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. :P
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

Write a Comment on Criando extensão para php

Subscribe

Follow comments by subscribing to the Criando extensão para php Comments RSS feed.

More

Read more posts by Mathias Grimm

Por dentro de um Template Engine Dreamm - Gerador de código fonte