Einführung in die Erstellung eines mysqlnd-Plugins

Es ist wichtig zu bedenken, dass ein mysqlnd-Plugin selbst eine PHP-Erweiterung ist.

Der folgende Code zeigt die grundlegende Struktur der MINIT-Funktion, die in einem typischen mysqlnd-Plugin verwendet wird:

 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)() { } 

Analyse der Aufgaben: von C zum Userspace

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

Ablauf:

  1. PHP: Benutzer registriert den Plugin-Callback

  2. PHP: Benutzer ruft eine beliebige PHP-MySQL-API auf, um sich mit MySQL zu verbinden

  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; }

Aufruf des Userspaces: einfache Argumente

 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); } } 

Aufruf des Userspaces: Strukturen als Argumente

 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); } } 

Bei vielen mysqlnd-Methoden ist das erste Argument ein C-"Objekt". Zum Beispiel ist das erste Argument der Methode connect() ein Zeiger auf MYSQLND. Die Struktur MYSQLND stellt ein mysqlnd-Verbindungsobjekt dar.

Der Zeiger auf das mysqlnd-Verbindungsobjekt kann mit einem Standard-I/O-Dateihandle verglichen werden. Genau wie ein Standard-I/O-Dateihandle muss ein mysqlnd-Verbindungsobjekt mit Hilfe einer PHP-Variablen vom Typ Ressource mit dem Userspace verbunden werden.

Von C zum Userspace und zurück

 class proxy extends mysqlnd_plugin_connection { public function connect($conn, $host, ...) { printf("Verbinden mit dem Host '%s'\n", $host); debug_print_backtrace(); return parent::connect($conn); } public function query($conn, $query) { $ret = parent::query($conn, $query); printf("Abfrage = '%s'\n", $query); return $ret; } } mysqlnd_plugin_set_conn_proxy(new proxy()); 

PHP-Benutzer müssen die Möglichkeit haben, die übergeordnete Implementierung einer überschriebenen Methode aufzurufen.

Durch Vererbung ist es möglich, nur ausgewählte Methoden zu "verfeinern", und man kann wählen, wann der eigene Code ausgeführt werden soll, vor oder nach der übergeordneten Methode ("pre"- oder "post"-Hook).

Erstellen der Klasse: 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-Verbindung", le_mysqlnd_plugin_conn); if (PASS == org_methods.connect(conn, host, TSRMLS_CC)) RETVAL_TRUE; else RETVAL_FALSE; } 
To Top