Bien commencer la compilation d'un plugin mysqlnd

Il est important de se souvenir qu'un plugin mysqlnd est lui-même une extension PHP.

Le code suivant montre la structure basique d'une fonction MINIT utilisée dans un plugin typique mysqlnd :

 static PHP_MINIT_FUNCTION(mysqlnd_plugin) { mysqlnd_plugin_id = mysqlnd_plugin_register(); conn_m = mysqlnd_get_conn_methods(); memcpy(org_conn_m, conn_m, sizeof(struct st_mysqlnd_conn_methods)); conn_m->query = MYSQLND_METHOD(mysqlnd_plugin_conn, query); conn_m->connect = MYSQLND_METHOD(mysqlnd_plugin_conn, connect); } 
 enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, query)() { } enum_func_status MYSQLND_METHOD(mysqlnd_plugin_conn, connect)() { } 

Tâche d'analyse : depuis C vers l'espace utilisateur

 class proxy extends mysqlnd_plugin_connection { public function connect($host, ...) { .. } } mysqlnd_plugin_set_conn_proxy(new proxy()); 

Process:

  1. PHP : l'utilisateur enregistre une fonction de rappel pour le plugin

  2. PHP : l'utilisateur appelle une méthode de l'API PHP MySQL pour se connecter à MySQL

  3. C : ext MYSQLND_METHOD(my_conn_class,connect)( MYSQLND *conn, const char *host TSRMLS_DC) { enum_func_status ret = FAIL; zval * global_user_conn_proxy = fetch_userspace_proxy(); if (global_user_conn_proxy) { ret = MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, host, ); } else { ret = org_methods.connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket, mysql_flags TSRMLS_CC); } return ret; }

Appel de l'espace utilisateur: arguments simples

 MYSQLND_METHOD(my_conn_class,connect)( , const char *host, ) { if (global_user_conn_proxy) { zval* zv_host; MAKE_STD_ZVAL(zv_host); ZVAL_STRING(zv_host, host, 1); MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, zv_retval, zv_host ); zval_ptr_dtor(&zv_host); } } 

Appel de l'espace utilisateur : structures comme arguments

 MYSQLND_METHOD(my_conn_class, connect)( MYSQLND *conn, ) { if (global_user_conn_proxy) { zval* zv_conn; ZEND_REGISTER_RESOURCE(zv_conn, (void *)conn, le_mysqlnd_plugin_conn); MY_ZEND_CALL_METHOD_WRAPPER(global_user_conn_proxy, zv_retval, zv_conn, zv_host ); zval_ptr_dtor(&zv_conn); } } 

Le premier argument de toutes les méthodes mysqlnd est un objet C. Par exemple, le premier argument de la méthode connect() est un pointeur vers MYSQLND. La structure MYSQLND représente un objet de connexion mysqlnd.

Le pointeur de l'objet de connexion mysqlnd peut être comparé à un pointeur de fichier standard I/O. Tout comme un pointeur de fichier standard I/O, un objet de connexion mysqlnd doit être lié à l'espace utilisateur en utilisant une variable PHP de type ressource.

Depuis C vers l'espace utilisateur, puis, retour

 class proxy extends mysqlnd_plugin_connection { public function connect($conn, $host, ...) { printf("Connexion à l'hôte = '%s'\n", $host); debug_print_backtrace(); return parent::connect($conn); } public function query($conn, $query) { $ret = parent::query($conn, $query); printf("Requête = '%s'\n", $query); return $ret; } } mysqlnd_plugin_set_conn_proxy(new proxy()); 

Les utilisateurs PHP doivent pouvoir appeler l'implémentation du parent d'une méthode écrasée.

Comme résultat d'un sous-classement, il est possible de redéfinir uniquement les méthodes sélectionnées, et vous pouvez choisir d'avoir des actions "pre" ou "post".

Construction d'une classe : mysqlnd_plugin_connection::connect()

 PHP_METHOD("mysqlnd_plugin_connection", connect) { zval* mysqlnd_rsrc; MYSQLND* conn; char* host; int host_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mysqlnd_rsrc, &host, &host_len) == FAILURE) { RETURN_NULL(); } ZEND_FETCH_RESOURCE(conn, MYSQLND* conn, &mysqlnd_rsrc, -1, "Mysqlnd Connection", le_mysqlnd_plugin_conn); if (PASS == org_methods.connect(conn, host, TSRMLS_CC)) RETVAL_TRUE; else RETVAL_FALSE; } 
To Top