mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-19 10:28:54 +00:00

git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@325471 c90b9560-bf6c-de11-be94-00142212c4b1
424 lines
16 KiB
XML
424 lines
16 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
<chapter xml:id="mysqlnd-uh.quickstart" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>Quickstart and Examples</title>
|
|
<para>
|
|
The mysqlnd user handler plugin can be understood as a client-side proxy
|
|
for all PHP MySQL extensions (<link linkend="ref.mysqli">mysqli</link>,
|
|
<link linkend="ref.mysql">mysql</link>,
|
|
<link linkend="ref.pdo-mysql">PDO_MYSQL</link>), if they are compiled to
|
|
use the <link linkend="book.mysqlnd">mysqlnd</link> library. The
|
|
extensions use the <literal>mysqlnd</literal> library internally, at the C
|
|
level, to communicate with the MySQL server. PECL/mysqlnd_uh
|
|
allows it to hook many <literal>mysqlnd</literal> calls. Therefore,
|
|
most activities of the PHP MySQL extensions can be monitored.
|
|
</para>
|
|
<para>
|
|
Because monitoring happens at the level of the library, at a layer below the
|
|
application, it is possible to monitor applications without changing them.
|
|
</para>
|
|
<para>
|
|
On the C level, the <literal>mysqlnd</literal> library is structured in modules
|
|
or classes. The extension hooks almost all methods of the <literal>mysqlnd</literal>
|
|
internal <literal>connection</literal> class and exposes them through the
|
|
user space class <classname>MysqlndUhConnection</classname>. Some few methods of
|
|
the mysqlnd internal <literal>statement</literal> class are made available
|
|
to the PHP user with the class <classname>MysqlndUhPreparedStatement</classname>.
|
|
By subclassing the classes <classname>MysqlndUhConnection</classname> and
|
|
<classname>MysqlndUhPreparedStatement</classname> users get access to
|
|
<literal>mysqlnd</literal> internal function calls.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
The internal <literal>mysqlnd</literal> function calls are not designed
|
|
to be exposed to the PHP user. Manipulating their activities may
|
|
cause PHP to crash or leak memory. Often, this is not considered a bug. Please,
|
|
keep in mind that you are accessing C library functions through
|
|
PHP which are expected to take certain actions, which you may not be able to
|
|
emulate in user space. Therefore, it is strongly recommended to always call
|
|
the parent method implementation when subclassing <classname>MysqlndUhConnection</classname>
|
|
or <classname>MysqlndUhPreparedStatement</classname>. To prevent the worst
|
|
case, the extension performs some sanity checks. Please, see also the
|
|
<link linkend="mysqlnd-uh.configuration">Mysqlnd_uh &ConfigureOptions;</link>.
|
|
</para>
|
|
</note>
|
|
|
|
|
|
<section xml:id="mysqlnd-uh.quickstart.configuration">
|
|
<title>Setup</title>
|
|
<para>
|
|
The plugin is implemented as a PHP extension. See the
|
|
<link linkend="mysqlnd-uh.installation">installation instructions</link> to
|
|
install the
|
|
<link xlink:href="&url.pecl.package;mysqlnd_ms">PECL/mysqlnd_uh</link> extension.
|
|
Then, load the extension into PHP and activate the plugin in the PHP configuration
|
|
file using the PHP configuration directive named
|
|
<link linkend="ini.mysqlnd-uh.enable">mysqlnd_uh.enable</link>.
|
|
The below example shows the default settings of the extension.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Enabling the plugin (php.ini)</title>
|
|
<programlisting role="ini">
|
|
<![CDATA[
|
|
mysqlnd_uh.enable=1
|
|
mysqlnd_uh.report_wrong_types=1
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
</section>
|
|
|
|
<section xml:id="mysqlnd-uh.quickstart.how-it-works">
|
|
<title>How it works</title>
|
|
<para>
|
|
This describes the background and inner workings of the mysqlnd_uh
|
|
extension.
|
|
</para>
|
|
<para>
|
|
Two classes are provided by the extension: <classname>MysqlndUhConnection</classname>
|
|
and <classname>MysqlndUhPreparedStatement</classname>. <classname>MysqlndUhConnection</classname> lets
|
|
you access almost all methods of the <literal>mysqlnd</literal>
|
|
internal <literal>connection</literal> class. The latter exposes some selected
|
|
methods of the <literal>mysqlnd</literal> internal <literal>statement</literal> class.
|
|
For example, <methodname>MysqlndUhConnection::connect</methodname> maps to
|
|
the <literal>mysqlnd</literal> library C function
|
|
<literal>mysqlnd_conn__connect</literal>.
|
|
</para>
|
|
<para>
|
|
As a mysqlnd plugin, the PECL/mysqlnd_uh extension replaces <literal>mysqlnd</literal>
|
|
library C functions with its own functions. Whenever a
|
|
PHP MySQL extension compiled to use <literal>mysqlnd</literal> calls
|
|
a mysqlnd function, the functions installed by the plugin are executed
|
|
instead of the original <literal>mysqlnd</literal> ones. For example,
|
|
<function>mysqli_connect</function> invokes <literal>mysqlnd_conn__connect</literal>,
|
|
so the connect function installed by PECL/mysqlnd_uh will be called.
|
|
The functions installed by PECL/mysqlnd_uh are the methods of the built-in classes.
|
|
</para>
|
|
<para>
|
|
The built-in PHP classes and their methods do nothing but call their
|
|
<literal>mysqlnd</literal> C library counterparts, to behave exactly
|
|
like the original <literal>mysqlnd</literal> function they replace.
|
|
The code below illustrates in pseudo-code what the extension does.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Pseudo-code: what a built-in class does</title>
|
|
<programlisting>
|
|
<![CDATA[
|
|
class MysqlndUhConnection {
|
|
public function connect(($conn, $host, $user, $passwd, $db, $port, $socket, $mysql_flags) {
|
|
MYSQLND* c_mysqlnd_connection = convert_from_php_to_c($conn);
|
|
...
|
|
return call_c_function(mysqlnd_conn__connect(c_mysqlnd_connection, ...));
|
|
}
|
|
}
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
The build-in classes behave like a transparent proxy. It is possible for
|
|
you to replace the proxy with your own. This is done by subclassing
|
|
<classname>MysqlndUhConnection</classname> or
|
|
<classname>MysqlndUhPreparedStatement</classname> to extend the functionality
|
|
of the proxy, followed by registering a new proxy object.
|
|
Proxy objects are installed by
|
|
<function>mysqlnd_uh_set_connection_proxy</function>
|
|
and
|
|
<function>mysqlnd_uh_set_statement_proxy</function>.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Installing a proxy</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class proxy extends MysqlndUhConnection {
|
|
public function connect($res, $host, $user, $passwd, $db, $port, $socket, $mysql_flags) {
|
|
printf("%s(%s)\n", __METHOD__, var_export(func_get_args(), true));
|
|
$ret = parent::connect($res, $host, $user, $passwd, $db, $port, $socket, $mysql_flags);
|
|
printf("%s returns %s\n", __METHOD__, var_export($ret, true));
|
|
return $ret;
|
|
}
|
|
}
|
|
mysqlnd_uh_set_connection_proxy(new proxy());
|
|
|
|
$mysqli = new mysqli("localhost", "root", "", "test");
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
proxy::connect(array (
|
|
0 => NULL,
|
|
1 => 'localhost',
|
|
2 => 'root',
|
|
3 => '',
|
|
4 => 'test',
|
|
5 => 3306,
|
|
6 => NULL,
|
|
7 => 131072,
|
|
))
|
|
proxy::connect returns true
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
</section>
|
|
|
|
<section xml:id="mysqlnd-uh.quickstart.proxy-installation">
|
|
<title>Installing a proxy</title>
|
|
<para>
|
|
The extension provides two built-in classes: <classname>MysqlndUhConnection</classname>
|
|
and <classname>MysqlndUhPreparedStatement</classname>. The classes are used
|
|
for hooking <literal>mysqlnd</literal> library calls. Their methods correspond
|
|
to <literal>mysqlnd</literal> internal functions. By default they act like
|
|
a transparent proxy and do nothing but call their <literal>mysqlnd</literal> counterparts.
|
|
By subclassing the classes you can install your own proxy to monitor <literal>mysqlnd</literal>.
|
|
</para>
|
|
<para>
|
|
See also the <link linkend="mysqlnd-uh.quickstart.how-it-works">How it works</link>
|
|
guide to learn about the inner workings of this extension.
|
|
</para>
|
|
<para>
|
|
Connection proxies are objects of the type <classname>MysqlndUhConnection</classname>.
|
|
Connection proxy objects are installed by
|
|
<function>mysqlnd_uh_set_connection_proxy</function>.
|
|
If you install the built-in class <classname>MysqlndUhConnection</classname>
|
|
as a proxy, nothing happens. It behaves like a transparent proxy.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Proxy registration, mysqlnd_uh.enable=1</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
mysqlnd_uh_set_connection_proxy(new MysqlndUhConnection());
|
|
$mysqli = new mysqli("localhost", "root", "", "test");
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
The <literal>PHP_INI_SYSTEM</literal> configuration setting
|
|
<literal><link linkend="ini.mysqlnd-uh.enable">mysqlnd_uh.enable</link></literal>
|
|
controls whether a proxy may be set. If disabled, the extension
|
|
will throw errors of type <literal>E_WARNING</literal>
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Proxy installation disabled</title>
|
|
<programlisting role="ini">
|
|
<![CDATA[
|
|
mysqlnd_uh.enable=0
|
|
]]>
|
|
</programlisting>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
mysqlnd_uh_set_connection_proxy(new MysqlndUhConnection());
|
|
$mysqli = new mysqli("localhost", "root", "", "test");
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
PHP Warning: MysqlndUhConnection::__construct(): (Mysqlnd User Handler) The plugin has been disabled by setting the configuration parameter mysqlnd_uh.enabled = false. You must not use any of the base classes in %s on line %d
|
|
PHP Warning: mysqlnd_uh_set_connection_proxy(): (Mysqlnd User Handler) The plugin has been disabled by setting the configuration parameter mysqlnd_uh.enable = false. The proxy has not been installed in %s on line %d
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
To monitor <literal>mysqlnd</literal>, you have to write your own
|
|
proxy object subclassing <classname>MysqlndUhConnection</classname>.
|
|
Please, see the function reference for a the list of methods that
|
|
can be subclassed. Alternatively, you can use reflection to inspect
|
|
the built-in <classname>MysqlndUhConnection</classname>.
|
|
</para>
|
|
<para>
|
|
Create a new class <literal>proxy</literal>. Derive it from the
|
|
built-in class <classname>MysqlndUhConnection</classname>.
|
|
Replace the
|
|
<function>MysqlndUhConnection::connect</function>.
|
|
method. Print out the host parameter value passed to the method.
|
|
Make sure that you call the parent implementation of the <literal>connect</literal>
|
|
method. Failing to do so may give unexpected and undesired results, including
|
|
memory leaks and crashes.
|
|
</para>
|
|
<para>
|
|
Register your proxy and open three connections using the PHP MySQL
|
|
extensions <link linkend="ref.mysqli">mysqli</link>,
|
|
<link linkend="ref.mysql">mysql</link>,
|
|
<link linkend="ref.pdo-mysql">PDO_MYSQL</link>. If the extensions have been
|
|
compiled to use the <literal>mysqlnd</literal> library, the
|
|
<literal>proxy::connect</literal> method will be called three times, once
|
|
for each connection opened.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Connection proxy</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class proxy extends MysqlndUhConnection {
|
|
public function connect($res, $host, $user, $passwd, $db, $port, $socket, $mysql_flags) {
|
|
printf("Connection opened to '%s'\n", $host);
|
|
/* Always call the parent implementation! */
|
|
return parent::connect($res, $host, $user, $passwd, $db, $port, $socket, $mysql_flags);
|
|
}
|
|
}
|
|
mysqlnd_uh_set_connection_proxy(new proxy());
|
|
|
|
$mysqli = new mysqli("localhost", "root", "", "test");
|
|
$mysql = mysql_connect("localhost", "root", "");
|
|
$pdo = new PDO("mysql:host=localhost;dbname=test", "root", "");
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Connection opened to 'localhost'
|
|
Connection opened to 'localhost'
|
|
Connection opened to 'localhost'
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
The use of prepared statement proxies follows the same pattern: create a
|
|
proxy object of the type <classname>MysqlndUhPreparedStatement</classname>
|
|
and install the proxy using
|
|
<function>mysqlnd_uh_set_statement_proxy</function>.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Prepared statement proxy</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class stmt_proxy extends MysqlndUhPreparedStatement {
|
|
public function prepare($res, $query) {
|
|
printf("%s(%s)\n", __METHOD__, $query);
|
|
return parent::prepare($res, $query);
|
|
}
|
|
}
|
|
mysqlnd_uh_set_statement_proxy(new stmt_proxy());
|
|
|
|
$mysqli = new mysqli("localhost", "root", "", "test");
|
|
$stmt = $mysqli->prepare("SELECT 'mysqlnd hacking made easy' AS _msg FROM DUAL");
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
stmt_proxy::prepare(SELECT 'mysqlnd hacking made easy' AS _msg FROM DUAL)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
</section>
|
|
|
|
<section xml:id="mysqlnd-uh.quickstart.query-monitoring">
|
|
<title>Basic query monitoring</title>
|
|
<para>
|
|
Basic monitoring of a query statement is easy with PECL/mysqlnd_uh.
|
|
Combined with <function>debug_print_backtrace</function> it can become a powerful
|
|
tool, for example, to find the origin of certain statement. This may
|
|
be desired when searching for slow queries but also after database
|
|
refactoring to find code still accessing deprecated databases or
|
|
tables. The latter may be a complicated matter to do otherwise, especially if
|
|
the application uses auto-generated queries.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>Basic Monitoring</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class conn_proxy extends MysqlndUhConnection {
|
|
public function query($res, $query) {
|
|
debug_print_backtrace();
|
|
return parent::query($res, $query);
|
|
}
|
|
}
|
|
class stmt_proxy extends MysqlndUhPreparedStatement {
|
|
public function prepare($res, $query) {
|
|
debug_print_backtrace();
|
|
return parent::prepare($res, $query);
|
|
}
|
|
}
|
|
mysqlnd_uh_set_connection_proxy(new conn_proxy());
|
|
mysqlnd_uh_set_statement_proxy(new stmt_proxy());
|
|
|
|
printf("Proxies installed...\n");
|
|
$pdo = new PDO("mysql:host=localhost;dbname=test", "root", "");
|
|
var_dump($pdo->query("SELECT 1 AS _one FROM DUAL")->fetchAll(PDO::FETCH_ASSOC));
|
|
|
|
$mysqli = new mysqli("localhost", "root", "", "test");
|
|
$mysqli->prepare("SELECT 1 AS _two FROM DUAL");
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
#0 conn_proxy->query(Resource id #19, SELECT 1 AS _one FROM DUAL)
|
|
#1 PDO->query(SELECT 1 AS _one FROM DUAL) called at [example.php:19]
|
|
array(1) {
|
|
[0]=>
|
|
array(1) {
|
|
["_one"]=>
|
|
string(1) "1"
|
|
}
|
|
}
|
|
#0 stmt_proxy->prepare(Resource id #753, SELECT 1 AS _two FROM DUAL)
|
|
#1 mysqli->prepare(SELECT 1 AS _two FROM DUAL) called at [example.php:22]
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
For basic query monitoring you should install a connection and a prepared statement
|
|
proxy. The connection proxy should subclass <function>MysqlndUhConnection::query</function>.
|
|
All database queries not using native prepared statements will call this method.
|
|
In the example the <literal>query</literal> function is invoked by a PDO call.
|
|
By default, <literal>PDO_MySQL</literal> is using prepared statement emulation.
|
|
</para>
|
|
<para>
|
|
All native prepared statements are prepared with the <literal>prepare</literal>
|
|
method of <literal>mysqlnd</literal> exported through
|
|
<methodname>MysqlndUhPreparedStatement::prepare</methodname>. Subclass
|
|
<classname>MysqlndUhPreparedStatement</classname> and overwrite <literal>prepare</literal>
|
|
for native prepared statement monitoring.
|
|
</para>
|
|
</section>
|
|
|
|
|
|
</chapter>
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
indent-tabs-mode:nil
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|