From 9c9b8f3e66ec3cb9a2e638bec8d2be2b8cfc0ff2 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela <tekiela246@gmail.com> Date: Mon, 22 Mar 2021 17:10:20 +0100 Subject: [PATCH] Improve mysqli_query docs * Add a nice big SQL injection warning * Break overlong breaks * Rewrite result_mode explanation * Simplify examples * Add mysqli_prepare to see also Closes GH-497. --- reference/mysqli/mysqli/query.xml | 129 +++++++++++-------------- reference/mysqli/mysqli/real-query.xml | 16 ++- 2 files changed, 71 insertions(+), 74 deletions(-) diff --git a/reference/mysqli/mysqli/query.xml b/reference/mysqli/mysqli/query.xml index 4805db6150..3df7427eed 100644 --- a/reference/mysqli/mysqli/query.xml +++ b/reference/mysqli/mysqli/query.xml @@ -77,29 +77,46 @@ <para> The query string. </para> - <para> - Data inside the query should be <link linkend="mysqli.real-escape-string">properly escaped</link>. - </para> + <warning> + <title>Security warning: SQL injection</title> + <para> + If the query contains any variable input then + <link linkend="mysqli.quickstart.prepared-statements">parameterized + prepared statements</link> should be used instead. Alternatively, the + data must be properly formatted and all strings must be escaped using + the <function>mysqli_real_escape_string</function> + function. + </para> + </warning> </listitem> </varlistentry> <varlistentry> <term><parameter>result_mode</parameter></term> <listitem> <para> - Either the constant <constant>MYSQLI_USE_RESULT</constant> or - <constant>MYSQLI_STORE_RESULT</constant> depending on the desired - behavior. By default, <constant>MYSQLI_STORE_RESULT</constant> is used. + The result mode can be one of 3 constants indicating how the result will + be returned from the MySQL server. </para> <para> - If you use <constant>MYSQLI_USE_RESULT</constant> all subsequent calls - will return error <literal>Commands out of sync</literal> unless you - call <function>mysqli_free_result</function> + <constant>MYSQLI_STORE_RESULT</constant> (default) - returns a + <classname>mysqli_result</classname> object with buffered result set. </para> <para> - With <constant>MYSQLI_ASYNC</constant> (available with mysqlnd), it is - possible to perform query asynchronously. + <constant>MYSQLI_USE_RESULT</constant> - returns a + <classname>mysqli_result</classname> object with unbuffered result set. + As long as there are pending records waiting to be fetched, the + connection line will be busy and all subsequent calls will return error + <literal>Commands out of sync</literal>. To avoid the error all records + must be fetched from the server or the result set must be discarded by + calling <function>mysqli_free_result</function>. + </para> + <para> + <constant>MYSQLI_ASYNC</constant> (available with mysqlnd) - the query is + performed asynchronously and no result set is immediately returned. <function>mysqli_poll</function> is then used to get results from such - queries. + queries. Used in combination with either + <constant>MYSQLI_STORE_RESULT</constant> or + <constant>MYSQLI_USE_RESULT</constant> constant. </para> </listitem> </varlistentry> @@ -110,9 +127,11 @@ <refsect1 role="returnvalues"> &reftitle.returnvalues; <para> - Returns &false; on failure. For successful queries which produce a result set, such as <literal>SELECT, SHOW, DESCRIBE</literal> or + Returns &false; on failure. For successful queries which produce a result + set, such as <literal>SELECT, SHOW, DESCRIBE</literal> or <literal>EXPLAIN</literal>, <function>mysqli_query</function> will return - a <classname>mysqli_result</classname> object. For other successful queries, <function>mysqli_query</function> will + a <classname>mysqli_result</classname> object. For other successful queries, + <function>mysqli_query</function> will return &true;. </para> </refsect1> @@ -125,90 +144,59 @@ <programlisting role="php"> <![CDATA[ <?php + +mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $mysqli = new mysqli("localhost", "my_user", "my_password", "world"); -/* check connection */ -if ($mysqli->connect_errno) { - printf("Connect failed: %s\n", $mysqli->connect_error); - exit(); -} - /* Create table doesn't return a resultset */ -if ($mysqli->query("CREATE TEMPORARY TABLE myCity LIKE City") === TRUE) { - printf("Table myCity successfully created.\n"); -} +$mysqli->query("CREATE TEMPORARY TABLE myCity LIKE City"); +printf("Table myCity successfully created.\n"); /* Select queries return a resultset */ -if ($result = $mysqli->query("SELECT Name FROM City LIMIT 10")) { - printf("Select returned %d rows.\n", $result->num_rows); - - /* free result set */ - $result->close(); -} +$result = $mysqli->query("SELECT Name FROM City LIMIT 10"); +printf("Select returned %d rows.\n", $result->num_rows); /* If we have to retrieve large amount of data we use MYSQLI_USE_RESULT */ -if ($result = $mysqli->query("SELECT * FROM City", MYSQLI_USE_RESULT)) { +$result = $mysqli->query("SELECT * FROM City", MYSQLI_USE_RESULT); - /* Note, that we can't execute any functions which interact with the - server until result set was closed. All calls will return an - 'out of sync' error */ - if (!$mysqli->query("SET @a:='this will not work'")) { - printf("Error: %s\n", $mysqli->error); - } - $result->close(); -} - -$mysqli->close(); -?> +/* Note, that we can't execute any functions which interact with the + server until all records have been fully retrieved or the result + set was closed. All calls will return an 'out of sync' error */ +$mysqli->query("SET @a:='this will not work'"); ]]> </programlisting> <para>&style.procedural;</para> <programlisting role="php"> <![CDATA[ <?php + +mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $link = mysqli_connect("localhost", "my_user", "my_password", "world"); -/* check connection */ -if (mysqli_connect_errno()) { - printf("Connect failed: %s\n", mysqli_connect_error()); - exit(); -} - /* Create table doesn't return a resultset */ -if (mysqli_query($link, "CREATE TEMPORARY TABLE myCity LIKE City") === TRUE) { - printf("Table myCity successfully created.\n"); -} +mysqli_query($link, "CREATE TEMPORARY TABLE myCity LIKE City"); +printf("Table myCity successfully created.\n"); /* Select queries return a resultset */ -if ($result = mysqli_query($link, "SELECT Name FROM City LIMIT 10")) { - printf("Select returned %d rows.\n", mysqli_num_rows($result)); - - /* free result set */ - mysqli_free_result($result); -} +$result = mysqli_query($link, "SELECT Name FROM City LIMIT 10"); +printf("Select returned %d rows.\n", mysqli_num_rows($result)); /* If we have to retrieve large amount of data we use MYSQLI_USE_RESULT */ -if ($result = mysqli_query($link, "SELECT * FROM City", MYSQLI_USE_RESULT)) { +$result = mysqli_query($link, "SELECT * FROM City", MYSQLI_USE_RESULT); - /* Note, that we can't execute any functions which interact with the - server until result set was closed. All calls will return an - 'out of sync' error */ - if (!mysqli_query($link, "SET @a:='this will not work'")) { - printf("Error: %s\n", mysqli_error($link)); - } - mysqli_free_result($result); -} - -mysqli_close($link); -?> +/* Note, that we can't execute any functions which interact with the + server until all records have been fully retrieved or the result + set was closed. All calls will return an 'out of sync' error */ +mysqli_query($link, "SET @a:='this will not work'"); ]]> </programlisting> - &examples.outputs; + &examples.outputs.similar; <screen> <![CDATA[ Table myCity successfully created. Select returned 10 rows. -Error: Commands out of sync; You can't run this command now + +Fatal error: Uncaught mysqli_sql_exception: Commands out of sync; you can't run this command now in... ]]> </screen> </example> @@ -220,6 +208,7 @@ Error: Commands out of sync; You can't run this command now <simplelist> <member><function>mysqli_real_query</function></member> <member><function>mysqli_multi_query</function></member> + <member><function>mysqli_prepare</function></member> <member><function>mysqli_free_result</function></member> </simplelist> </para> diff --git a/reference/mysqli/mysqli/real-query.xml b/reference/mysqli/mysqli/real-query.xml index 59d170385d..e4e5f08fc5 100644 --- a/reference/mysqli/mysqli/real-query.xml +++ b/reference/mysqli/mysqli/real-query.xml @@ -40,11 +40,19 @@ <term><parameter>query</parameter></term> <listitem> <para> - The query, as a string. - </para> - <para> - Data inside the query should be <link linkend="mysqli.real-escape-string">properly escaped</link>. + The query string. </para> + <warning> + <title>Security warning: SQL injection</title> + <para> + If the query contains any variable input then + <link linkend="mysqli.quickstart.prepared-statements">parameterized + prepared statements</link> should be used instead. Alternatively, the + data must be properly formatted and all strings must be escaped using + the <function>mysqli_real_escape_string</function> + function. + </para> + </warning> </listitem> </varlistentry> </variablelist>