pecl kiterjesztés írása

A múltkori téma ürügyén elkezdtem php kiterjesztést írni és két dologra jöttem rá: régen programoztam c-ben és kissé alul dokumentált a téma.

Emlékeztető gyanánt és ha esetleg valakinek gyorsan kell valami használható leírás, egy-két bejegyzést szeretnék szentelni a témának, ahogy haladok. A leírás készítésekor feltételezek minimális előműveltséget (pl nem fogom leírni step by step mi kell a forgatáshoz).

Az alap telepítéshez a fejlesztői eszközökön kívül a php5-dev csomag kell (meglepő :), és a php5 forrása. Utóbbiban található meg az ext_skel parancs ami létrehoz egy üres kiterjesztést. php5-dev hozza magával a phpize programot ami az üres kiterjesztést fordítható állapotba hozza.

apt-get source php5
apt-get install php5-dev

Egy homokozó kiterjesztést fogunk csinálni amibe beleteszünk ezt-azt.

cd php5*/ext
./ext_skel --extname=sandbox

Szedjünk ki pár feleslegeset. Következő fájlokban fogunk turkálni leginkább:

  • config.m4
  • sandbox.c
  • php_sandbox.h

config.m4

Ahogy látjuk a commentek dnl karakterekkel kezdődő sorok.

Érdemes itt bennhagyni amit alapból betett, mert ha külső lib-hez akarunk binding-et készíteni akkor csak ki kell szedni pár megjegyzést és a fordítási paraméterekhez hozzá is adta ami kell.

sandbox.c

Ez egy lényeges fájl, ennek szerkesztésével fogjuk tölteni időnk nagy részét.

A szerkezete a következő (szokott lenni, még nem):

include-ok, publikus függvények argumentum listái, függvénybejegyzések (lista ami a php számára összefoglalja hogy mely függvény milyen néven és arg. listával hívható), előzőek helyett lehetnek metódusok arg. listái vagy bejegyzések, modul összefoglaló, phpinfo táblázatot módosító hívások, php.ini definiálások, modul init és shoutdown hívások, erőforrás init és shoutdown hívások, függvények (metódusok) törzsei.

Nézzük mi nem kell ebből a fájlból:

/* If you declare any globals in php_sandbox.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(sandbox)
*/

...

	PHP_FE(confirm_sandbox_compiled,	NULL)		/* For testing, remove later. */

A sandbox_module_entry -t majd később vesszük kezelésbe, ez marad.

A PHP_INI_BEGIN kikommentezett részt ahogy van.

php_sandbox_init_globals se kell egyenlőre.

PHP_MINIT_FUNCTION, PHP_MSHUTDOWN_FUNCTION, PHP_RINIT_FUNCTION, PHP_RSHUTDOWN_FUNCTION.

PHP_MINFO_FUNCTION marad.

A PHP_FUNCTION(confirm_sandbox_compiled) -t a blokkot és a hozzá tartozó megjegyzéseket töröljük.

Térjünk vissza a sandbox_module_entry -hez és nézzük meg mi is ez:

zend_module_entry sandbox_module_entry = {
	STANDARD_MODULE_HEADER,
	"sandbox",
	sandbox_functions,
	PHP_MINIT(sandbox),
	PHP_MSHUTDOWN(sandbox),
	PHP_RINIT(sandbox),		/* Replace with NULL if there's nothing to do at request start */
	PHP_RSHUTDOWN(sandbox),	/* Replace with NULL if there's nothing to do at request end */
	PHP_MINFO(sandbox),
	"0.1", /* Replace with version number for your extension */
	STANDARD_MODULE_PROPERTIES
};

(mj: ifeket kiszedtem)

Ez a struktúra adja meg, hogy a php milyen hívást hol talál. Akármilyen nevet is adhatunk a többinek, ebben ha felsoroljuk, hogy mit hol talál a zend motor, akkor meg fogja találni.

  • Az elsővel és az utolsóval nem foglalkozunk, ezek jelenleg nem érdekesek.
  • következő a modul neve,
  • publikus függvény lista (zend_function_entry típusú sandbox_functions jelen példában)
  • modul inicializációs fv neve, ha nem használjuk NULL. Előbb töröltük tehát NULL.
  • modul leállításért felelős fv, ha nem használjuk NULL.
  • erőforrás init fv., vagy NULL
  • erőforrás kitisztító fv., vagy NULL
  • phpinfo táblázat bővítéséért felelős fv
  • verziószám, vagy NO_VERSION_YET

php_sandbox.h

Amiket kiszedtünk init, shoutdown és függvény fejlécek, innen is szedjük ki.

Első kódunk, helló világ.

Első függvényünk a következő fogja megcsinálni:

function hw()
{
  return 'Hello World\n';
}

A cben megír kód pedig így néz ki:

// Fv entry:

zend_function_entry sandbox_functions[] = {
  PHP_FE(hw,  NULL)
  {NULL, NULL, NULL}
};

// hw proto:

PHP_FUNCTION(hw)
{
  char *string;

  string = "Hello World!\n";
  RETURN_STRING(string, 1);
}

// php_sandbox.h:

PHP_FUNCTION(hw);

config.m4 -be hogy forduljon ami kell:

...
dnl config.m4 for extension sandbox 

PHP_ARG_WITH(sandbox,for sandbox support,
[  --with-sandbox    Include Sandbox support])

if test "$PHP_SANDBOX" != "no"; then
....
phpize; ./configure; make

Ha a kezdő állapotot szeretnénk kialakítani a könyvtárban akkor phpize –clean parancsot adjuk ki.

A lefordult modul a modules mappában van. Én innen egy symlinket készítettem a php5 ext könyvtárába (/usr/lib/php5/20060613+lfs), és létrehoztam a /etc/php5/cli/conf.d könyvtárba egy sandbox.ini -t a megfelelő tartalommal. Aztán ha valamit átírok akkor csak make kell és már tesztelhető a végeredmény egy másik terminálban.

Nézzük mit csinál amit alkottunk:

connor@tudor:~/Desktop$ php -r "echo hw();"

Ha ügyesek voltunk hiba nélkül kiírja “Hello World!”.

Második függvény és egy paraméter

Csináljunk egy másik fv-t is. Ez a következőt fogja csinálni:

function hello_user($name)
{
  return 'Hello '. $name .'!\n';
}

Tehát itt már lesz paraméter is a fv-hez.

Megfelelő kódok:

  PHP_FE(hello_user,  NULL)

/* {{{ proto string hello_user()
   Say hello to user. */
PHP_FUNCTION(hello_user)
{
  zval **username;
  char *retval;
  int len;

  if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &username) == FAILURE)
  {
    WRONG_PARAM_COUNT;
  }
  convert_to_string_ex(username);

  len = spprintf(&retval, 0, "Hello %s!\n", Z_STRVAL_PP(username));
  RETURN_STRINGL(retval, len, 1);
}
/* }}} */

php_sandbox.h

PHP_FUNCTION(hello_user);

Egy kis magyarázat a hello user blokkhoz:

  • zend_get_parameters_ex olvassa be a paramétert
  • WRONG_PARAM_COUNT makró dobja a hibát
  • convert_to_string_ex alakítja mindenképp string-é (különben egy lebegőpontossal vagy egy logikaival meggyűlne a bajunk)
  • Z_STRVAL_PP makró stringet eredményez c szinten is.

Kód próba:

connor@tudor:~$ php -r "echo hello_user();"

Warning: Wrong parameter count for hello_user() in Command line code on line 1
connor@tudor:~$ php -r "echo hello_user("Connor");"
Hello Connor!
connor@tudor:~$

Végül…

Remélem a jövőben is lesz rá módom hogy írjak a tapasztalatokról, ha más nem akkor a tervezett szóelválasztásos kiterjesztés megírását fogom lekörmölni. Érdemes már elkészült kiterjesztéseket is megnézni és azokból tanulni (én is így teszek).

Eddigi munka forrása.

Megj: Mivel az írás gyak. a saját jegyzeteim a témában így biztos van benne félrevezető infó és féligazság. Ha valamire rájövök, hogy nem pont az ahogy én azt elképzeltem javítom, de szívesen várom a hozzáértők javításait is. Ugyanez igaz a későbbi írásokra is. Ezeknek megfelelőek kéretik olvasni a leírtakat.