Mysqli query or die error

Какой код лучше использовать, чтобы отлавливать ошибки MySQL?

Подскажите, пожалуйста, какой код лучше использовать, чтобы отлавливать ошибки MySQL?

И почему один лучше другого?

  • Вопрос задан более трёх лет назад
  • 4567 просмотров

Оценить 1 комментарий

Если выбирать из этих двух, то второй, разумеется. Он на порядок лучше первого:
— в отличие от первого, он будет выдавать ошибки туда же, куда и весь остальной РНР. На машине разработчика это может быть экран, на боевом сайте — лог. Первый плюёт ошибки в браузер ВСЕГДА, чего на боевом сайте не должно быть никогда
— в отличие от первого, он сообщит номер строки и имя файла, где произошла ошибка, что является критически важным для того самого отлова ошибки. Рекомендую попробовать поискать ошибочный запрос в коде на пару тысяч строк по сообщению от первого варианта. Подробнее про то, как правильно обрабатывать ошибки, можно почитать здесь: Обработка ошибок, часть 1

Примечание: на самом деле ни тот, ни другой коды работать не будут, поскольку mysqli_error() тоже требует $link в обязательном порядке.

Дальше уже идут более продвинутые варианты.
Для начала, mysqli умеет кидать исключения из коробки:

и после этого любая ошибка mysqli будет порождать исключение.
Но у этого подхода есть два минуса:
1. Такой вариант может понадобиться только в случае, если обращения к mysqli_query разбросаны по всему коду, чего делать нельзя ни в коем случае.
2. В брошенном исключении будет отсутствовать сам запрос, который может быть очень полезен при отладке.

Поэтому идеальным вариантом будет такой:
Во-первых, все обращения к mysqli API в обязательном порядке надо завернуть в какую-либо библиотеку, которая возьмёт на себя выполнение всей грязной и повторяющейся работы. Пример такой библиотеки — SafeMysql
Во-вторых, в этой библиотеке оформить код обращения к mysqli_query такм образом:

В результате мы получим идеальную обработку ошибок:
— этот код уже из коробки будет так же следовать настройкам РНР, и не будет выдавать ошибки на экран на боевом сервере, но при этом программист всегда будет о ней проинформирован.
— этот код будет выдавать трассировку вызовов — бесценную информацию, без которой найти место, где произошла ошибка, будет очень сложно.
— брошенное исключение можно будет поймать в хендлере или блоке try..catch (однако если нет опыта работы с этими двумя вещами, то на первое время лучше оставить исключение как есть. В обработке ошибок есть много нюансов, неизвестных среднему кодеру, и поэтому лучше оставить эту задачу для РНР).

Источник

Подготовительные манипуляции для работы с SQL в PHP

Давайте теперь научимся работать с базами данных через PHP. Для этого прежде всего необходимо установить соединение с сервером базы данных.

Делается это с помощью функции mysql_connect , которая принимает 3 параметра: имя хоста (сервера), имя пользователя, под которым мы работаем с базой и пароль для этого пользователя.

Если вы работаете на своем компьютере, то это будут localhost , root и пароль в виде пустой строки (на некоторых серверах он тоже может быть root ). Если ваша база данных в интернете — то эти данные выдает вам хостинг.

Итак, давайте установим соединение с базой данных:

Если указанные нами доступы правильные, то установится соединение к базе данных. При этом в переменную $link запишется специальный объект соединения, который мы будем использовать в дальнейшем для всех обращений к нашей базе данных.

Посылаем запросы к базе данных

После соединения с базой к ней можно отправлять запросы. Это делается с помощью функции mysqli_query . Первым параметром эта функция принимает принимает переменную, в которую мы записали результат mysqli_connect , а вторым — строку с SQL запросом.

К примеру, выполним запрос, который достанет все записи из таблицы users :

Текст запроса не обязательно писать прямо в параметре функции mysqli_query . Давайте вынесем его в переменную:

Отлавливаем ошибки базы данных

Как вы уже знаете, в PHP вывод ошибок на экран включается с помощью функции error_reporting . Эта функция, однако, не включает вывод ошибок, допущенных в тексте SQL запроса.

Чтобы вывести ошибки SQL команд, следует пользоваться функцией mysqli_error , которую необходимо добавлять к каждому запросу к БД, вот так:

Пока не будем разбираться с тем, как работает эта конструкция. Просто добавляйте ее и, в случае ошибочного SQL запроса вы увидите сообщение об этом в окне браузера.

Тестируем работоспособность

Давайте теперь напишем тестовый код, который вы сможете запустить у себя, чтобы убедится в том, что у вас все подключилось верно.

Для начала убедитесь, что у вас есть база данных mydb , а в ней таблица users , заполненная какими-нибудь данными.

Затем запустите у себя следующий код:

Если на экране нет ошибок и вы видите результат var_dump — значит все хорошо. Если же есть какие-то ошибки — исправьте их и попробуйте снова.

Читайте также:  Error unregistered offending command show

Скопируйте и запустите у себя приведенный тестовый код.

Источник

mysqli::query

(PHP 5, PHP 7, PHP 8)

mysqli::query — mysqli_query — Performs a query on the database

Description

Performs a query against the database.

For non-DML queries (not INSERT, UPDATE or DELETE), this function is similar to calling mysqli_real_query() followed by either mysqli_use_result() or mysqli_store_result() .

In the case where a statement is passed to mysqli_query() that is longer than max_allowed_packet of the server, the returned error codes are different depending on whether you are using MySQL Native Driver ( mysqlnd ) or MySQL Client Library ( libmysqlclient ). The behavior is as follows:

mysqlnd on Linux returns an error code of 1153. The error message means got a packet bigger than max_allowed_packet bytes .

mysqlnd on Windows returns an error code 2006. This error message means server has gone away .

libmysqlclient on all platforms returns an error code 2006. This error message means server has gone away .

Parameters

Procedural style only: A mysqli object returned by mysqli_connect() or mysqli_init()

The query string.

Security warning: SQL injection

If the query contains any variable input then parameterized prepared statements should be used instead. Alternatively, the data must be properly formatted and all strings must be escaped using the mysqli_real_escape_string() function.

The result mode can be one of 3 constants indicating how the result will be returned from the MySQL server.

MYSQLI_STORE_RESULT (default) — returns a mysqli_result object with buffered result set.

MYSQLI_USE_RESULT — returns a mysqli_result 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 Commands out of sync . To avoid the error all records must be fetched from the server or the result set must be discarded by calling mysqli_free_result() .

MYSQLI_ASYNC (available with mysqlnd) — the query is performed asynchronously and no result set is immediately returned. mysqli_poll() is then used to get results from such queries. Used in combination with either MYSQLI_STORE_RESULT or MYSQLI_USE_RESULT constant.

Return Values

Returns false on failure. For successful queries which produce a result set, such as SELECT, SHOW, DESCRIBE or EXPLAIN , mysqli_query() will return a mysqli_result object. For other successful queries, mysqli_query() will return true .

Examples

Example #1 mysqli::query() example

( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT );
$mysqli = new mysqli ( «localhost» , «my_user» , «my_password» , «world» );

/* Create table doesn’t return a resultset */
$mysqli -> query ( «CREATE TEMPORARY TABLE myCity LIKE City» );
printf ( «Table myCity successfully created.\n» );

/* Select queries return a resultset */
$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 */
$result = $mysqli -> query ( «SELECT * FROM City» , MYSQLI_USE_RESULT );

/* 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'» );

( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT );
$link = mysqli_connect ( «localhost» , «my_user» , «my_password» , «world» );

/* Create table doesn’t return a resultset */
mysqli_query ( $link , «CREATE TEMPORARY TABLE myCity LIKE City» );
printf ( «Table myCity successfully created.\n» );

/* Select queries return a resultset */
$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 */
$result = mysqli_query ( $link , «SELECT * FROM City» , MYSQLI_USE_RESULT );

/* 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'» );

The above examples will output something similar to:

See Also

  • mysqli_real_query() — Execute an SQL query
  • mysqli_multi_query() — Performs one or more queries on the database
  • mysqli_prepare() — Prepares an SQL statement for execution
  • mysqli_free_result() — Frees the memory associated with a result

User Contributed Notes 21 notes

This may or may not be obvious to people but perhaps it will help someone.

When running joins in SQL you may encounter a problem if you are trying to pull two columns with the same name. mysqli returns the last in the query when called by name. So to get what you need you can use an alias.

Below I am trying to join a user id with a user role. in the first table (tbl_usr), role is a number and in the second is a text name (tbl_memrole is a lookup table). If I call them both as role I get the text as it is the last «role» in the query. If I use an alias then I get both as desired as shown below.

Читайте также:  Gt p1000 кастомная прошивка

= «SELECT a.uid, a.role AS roleid, b.role,
FROM tbl_usr a
INNER JOIN tbl_memrole b
ON a.role = b.id
» ;

if ( $result = $mysqli -> query ( $sql )) <
while( $obj = $result -> fetch_object ()) <
$line .= $obj -> uid ;
$line .= $obj -> role ;
$line .= $obj -> roleid ;
>
>
$result -> close ();
unset( $obj );
unset( $sql );
unset( $query );

?>
In this situation I guess I could have just renamed the role column in the first table roleid and that would have taken care of it, but it was a learning experience.

The cryptic «Couldn’t fetch mysqli» error message can mean any number of things, including:

1. You’re trying to use a database object that you’ve already closed (as noted by ceo at l-i-e dot com). Reopen your database connection, or find the call to ( $db ); ?> or -> close (); ?> and remove it.
2. Your MySQLi object has been serialized and unserialized for some reason. Define a wakeup function to re-create your database connection. http://php.net/__wakeup
3. Something besides you closed your mysqli connection (in particular, see http://bugs.php.net/bug.php?id=33772)
4. You mixed OOP and functional calls to the database object. (So, you have -> query () ?> in the same program as ( $db ) ?> ).

When calling multiple stored procedures, you can run into the following error: «Commands out of sync; you can’t run this command now».
This can happen even when using the close() function on the result object between calls.
To fix the problem, remember to call the next_result() function on the mysqli object after each stored procedure call. See example below:

// New Connection
$db = new mysqli ( ‘localhost’ , ‘user’ , ‘pass’ , ‘database’ );

// Check for errors
if( mysqli_connect_errno ()) <
echo mysqli_connect_error ();
>

// 1st Query
$result = $db -> query ( «call getUsers()» );
if( $result ) <
// Cycle through results
while ( $row = $result -> fetch_object ()) <
$user_arr [] = $row ;
>
// Free result set
$result -> close ();
$db -> next_result ();
>

// 2nd Query
$result = $db -> query ( «call getGroups()» );
if( $result ) <
// Cycle through results
while ( $row = $result -> fetch_object ()) <
$group_arr [] = $row ;
>
// Free result set
$result -> close ();
$db -> next_result ();
>
else echo( $db -> error );

// Close connection
$db -> close ();
?>

Here is an example of a clean query into a html table

while ( $row = $myquery -> fetch_assoc ()) < ?>

> ?>

First Name Last Name City
echo $row [ «firstname» ]; ?> echo $row [ «lastname» ]; ?> echo $row [ «city» ]; ?>

Use mysqli_query to call a stored procedure that returns a result set.

Here is a short example:

= new mysqli ( DBURI , DBUSER , DBPASS , DBNAME );
if ( mysqli_connect_errno ())
<
printf ( «Connection failed: %s\n» , mysqli_connect_error ());
exit();
>

$SQL = «CALL my_procedure( $something )» ;
if ( ( $result = $mysqli -> query ( $SQL ))=== false )
<
printf ( «Invalid query: %s\nWhole query: %s\n» , $mysqli -> error , $SQL );
exit();
>

while ( $myrow = $result -> fetch_array ( MYSQLI_ASSOC ))
<
$aValue []= $myrow [ «a» ];
$bValue []= $myrow [ «b» ];
>
$result -> close ();
$mysqli -> close ();
?>
I hope this saves someone some time.

I like to save the query itself in a log file, so that I don’t have to worry about whether the site is live.

For example, I might have a global function:

function UpdateLog ( $string , $logfile ) <
$fh = fopen ( $logfile , ‘a’ );
$fwrite ( $fh , strftime ( ‘%F %T %z’ ). » » . $string . «\n» ;
fclose ( $fh );
>
?>

Then in my mysql function error trapper, something like this:

= «Database error in [page].php / » ;
$error_msg .= mysqli_error ( $link ). » / » ;
$error_msg .= $query ;
UpdateLog ( $error_msg , DB_ERROR_LOG_FILE );
?>

I also include the remote IP, user agent, etc., but I left it out of these code samples. And have it e-mail me when an error is caught, too.

Translation:
«Couldn’t fetch mysqli»

You closed your connection and are trying to use it again.

It has taken me DAYS to figure out what this obscure error message means.

When building apps, i like to see the whole statement when if fails.
= «SELECT somecolumn FROM sometable» ; //some instruction
$r = mysqli_query ( $DBlink , $q ) or die( mysqli_error ( $DBlink ). » Q=» . $q );
?>
If theres an error (like my numerous typing mistakes) this shows the entire instruction.
Good for development (not so good on production servers — simply find and replace when finished: $r=mysqli_query($DBlink,$q); )

Hope it helps. Jon

Calling Stored Procedures

Beeners’ note/example will not work. Use mysqli_multi_query() to call a Stored Procedure. SP’s have a second result-set which contains the status: ‘OK’ or ‘ERR’. Using mysqli_query will not work, as there are multiple results.

= «CALL SomeSP(‘params’)» ;
if(! mysqli_multi_query ( $sqlLink , $sQuery )) <
// your error handler
>
$sqlResult = mysqli_store_result ( $sqlLink );

if( mysqli_more_results ( $this -> sqlLink )) //Catch ‘OK’/’ERR’
while( mysqli_next_result ( $this -> sqlLink ));
?>

You will have to rewrite/expand this a bit for more usability of course, but it’s just an example.

For those using with replication enabled on their servers, add a mysqli_select_db() statement before any data modification queries. MySQL replication does not handle statements with db.table the same and will not replicate to the slaves if a scheme is not selected before.

mysqli::query() can only execute one SQL statement.

Use mysqli::multi_query() when you want to run multiple SQL statements within one query.

Use difference collation/character for connect, result.
You can set the collation before your query.

E.g. want to set the collation to utf8_general_ci
you can send the query «SET NAMES ‘utf8′» first

=new mysqli ( ‘localhost’ , ‘root’ , ‘password’ , ‘test’ );
$mysqli -> query ( «SET NAMES ‘utf8′» );
$q = $mysqli -> query ( «select * from test» );
while( $r = $q -> fetch_assoc ()) <
print_r ( $r );
>
?>

There are many variables about character settings.
By running sql command, SHOW VARIABLES LIKE ‘char%’;
There are some variables control the character usage.

Also SET NAMES can repalce with one or some settings like SET character_set_results=’utf8′;

Hi, i created function that add a new table using array , i work with it on my projects .
/* this function was learned from PHP.net */
function array_keys_exist (& $key ,array & $array ) <
$keys = split ( «\|» , $key );
foreach( $keys as $key_s ) <
if( array_key_exists ( $key_s , $array )) return true ;
>
return false ;
>
/*and this is my function */
array_create_table (array & $array ) <
if( is_array ( $array )) <
$key = «table|rows|values» ;
$info = «» ;
if( array_keys_exist ( $key , $array )) <
if( is_array ( $array [ «rows» ]) and is_array ( $array [ «values» ]) )<

if( count ( $array [ «rows» ]) == count ( $array [ «values» ])) <
for( $i = 0 ; $i count ( $array [ «rows» ]); $i ++) <
$info = $info . » » . $array [ «rows» ][ $i ]. » » . $array [ «values» ][ $i ]. » NOT NULL » ;
if( $i count ( $array [ «rows» ])- 1 ) $info = $info . «,» ;
>
$query = «CREATE TABLE » . $this -> private_tables_name . $array [ «table» ]. » » ;
$query .= «( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, » . $info . » )» ;
return $query ;
>
>
>else return «Error» ;
>
>

/* the use is simple */
$database = new database (); // connection to database i used mysqli .
$array = array( «table» => «MRO» , «rows» =>array( «name» , «username» ) , «values» => array( «VARCHAR (50) » , » VARCHAR (50) » ) );

$query = array_create_table ( $array ); // convert and create the query .
if( $database -> query ( $query )) echo «Work» ; else echo «Error» ; // result : work

Building inserts can be annoying. This helper function inserts an array into a table, using the key names as column names:

private function store_array (& $data , $table , $mysqli )
<
$cols = implode ( ‘,’ , array_keys ( $data ));
foreach ( array_values ( $data ) as $value )
<
isset( $vals ) ? $vals .= ‘,’ : $vals = » ;
$vals .= ‘\» . $this -> mysql -> real_escape_string ( $value ). ‘\» ;
>
$mysqli -> real_query ( ‘INSERT INTO ‘ . $table . ‘ (‘ . $cols . ‘) VALUES (‘ . $vals . ‘)’ );
>
?>

Adapt it to your specific needs.

or you could just extend the class.
in my case i already had a wraper for the db so something like this was easy :

public function free($result) <

just tried it and it works like a charm 😉

This Is A Secure Way To Use mysqli::query
———————————————————
function secured_query ( $sql )
<
$connection = new mysqli ( $host , $username , $password , $name );

if ( $connection -> connect_error )
die( «Secured» );

$result = $connection -> query ( $sql );
if( $result == FALSE )
die( «Secured» );

$connection -> close ();
return $result ;
>
/*
$host —> DataBase IP Address
$username —> DataBase Username
$password —> DataBase Password
$name —> DataBase Name
*/
?>

Recently I had puzzling problem when performing DML queries, update in particular, each time a update query is called and then there are some more queries to follow this error will show on the page and go in the error_log:
«Fatal error: Exception thrown without a stack frame in Unknown on line 0»

The strange thing is that all queries go through just fine so it didn’t make much sense:

$update = mysqli_query($connection, $query_string);
if(!$update) <
echo ‘Houston we have a problem ‘.mysqli_error($connection);
exit;
>

In the above example «$update» is «true», mysqli_error() is empty and of course the update operation goes through, however the nasty super cryptic error appears on the page.
What makes even less sense to me is how I fixed it — just called «mysqli_free_result» after the update query and the problem was gone, however because mysqli_free_result is not supposed to be called after DML queries (to free what, a boolean? lol) it needs to be wrapped in a try catch block:

try <
mysqli_free_result($update);
>catch (Exception $e) <
//do nothing
>

So, I don’t know why but it seems that when DML queries are responsible for:
«Fatal error: Exception thrown without a stack frame in Unknown on line 0»
calling «mysqli_free_result» after the query seems to be fixing the issue

Источник

Smartadm.ru
Adblock
detector