Error accessing MySQL database with PHP object (nested queries) - php

I want to get some data from a Sphinx server and pass it to MySQL to execute some queries. I'm new to PHP so probably I'm missing something here. I've looked for similar questions but can't find anything so maybe you can help me.
The error is in the first while. I'm pretty sure it's due to the $rown variable but don't know the reason. (I've verified that I can retrieve data from the connections so it is passing the data where the error lies - could be the sql syntax of the query but that seems fine).
Edited the code thanks to the comments below, now I get the error: Warning: mysqli_fetch_object() expects parameter 1 to be mysqli_result, boolean given in C:\Apache24\htdocs\test3.php on line 20. This is because the query failed, I still suspect it is because $rown.
$sphinxcon = mysqli_connect...
$mysqlcon = mysqli_connect...
$query = "SELECT names FROM iproducts LIMIT 0,1000";
$raw_results= mysqli_query($sphinxcon, $query);
//Until here works ok, now I want to pass $raw_results to MySQL
while ($row = mysqli_fetch_object($raw_results)) {
$rown = $row->names;
$mquery = "SELECT text FROM claims WHERE EXISTS ($rown) LIMIT 0,1000";
$mysqlresults = mysqli_query($mysqlcon, $mquery);
while ($final = mysqli_fetch_object($mysqlresults)) //this is line 20
{
printf ("%s<br />", $final->text);
}
}
Thanks :)

Well $row contains an object, so would have to use it as such, maybe
$rown = (string)$row->names;
... assuming you want the variable to contain the 'names' attribute you just SELECTed from Sphinx index.
As for the mysql EXISTS(), no idea what you really doing here, seems confused. How you structured it currently suggests that 'names' attribute in sphinx contains a complete SELECT query, that mysql could execute for the exists condition. That seems unlikely.
Guessing you meaning to more normal query something like
$mquery = "SELECT text FROM claims WHERE text LIKE '%$rown%' LIMIT 0,1000";
But that is subject to SQL injection, particully if names might contain single quotes. SO should escape it. Perhaps
$rown = mysqli_real_escape_string($mysqlcon, $row->names);
But might be worth reading up on prepared queries.
btw, the 'Error' you getting, is because you creating an invalid query and not dealing with it. So $mysqlresults is FALSE.
$mysqlresults = mysqli_query($mysqlcon, $mquery) or die("Mysql Error: ".mysqli_error($link)."\n");

Related

PHP / mysqli: Prepared Statements with num_rows constantly returning nothing

In my test-surroundings there is a database containing some Person Information (Name, E-Mail, Adress etc.). These Informations can be inserted by anyone into the database via a form. In the background they are inserted with a parameterized INSERT into the database after submission.
What I now would like to do is to detect if some person tries to insert the same values into the database again, and if he does, not inserting the new values and instead showing an error message. (So every person name in the database is unique, there are no multiple rows linked to one name).
I had a numerous number of ideas on how to accomplish this. My first one was to use a query like REPLACE or INSERT IGNORE, but this method would not give me feedback so I can display the error message.
My second attempt was to first do a SELECT-query, checking if the row already exists, and if num_rows is greater than 0, exit with the error message (and else do the INSERT-part). For this to work I will have to use parameterized queries for the SELECT too, as I´m putting some user input into it. Figuring that parameterized queries need special functions for everything you could normally do with way less lines of code, I researched in the internet on how to get num_rows from my $statement parameterized-statement-object. This is what I had in the end:
$connection = new mysqli('x', 'x', 'x', 'x');
if (mysqli_connect_error()) {
die("Connect Error");
}
$connection->set_charset("UTF-8");
$statement = $connection->stmt_init();
$statement = $connection->prepare('SELECT Name FROM test WHERE Name LIKE ?');
flags = "s";
$statement->bind_param($flags, $_POST["person_name"]);
$statement->execute();
$statement->store_result();
$result = $statement->get_result(); //Produces error
if ($result->num_rows >= 1) {
$output = "Your already registered";
} else {
$output = "Registering you...";
}
exit($output);
After all, I can´t get why mysqli still won´t give me num_rows from my statement. Any help is appreciated, thanks in advance!
Oh, and if you guys could explain to me what I have to do to get affected_rows,that would be awesome!
EDIT: I know I could to this by using unique constraints. I also found out that I can find out if INSERT IGNORE skipped the INSERT or not. But that won´t answer my complete question: Why does the SELECT num_rows alternative not work?
ANOTHER EDIT: I changed the code snippet to what I now have. Although my mysql(i)-version seems to be 5.6.33 (I echo´d it via $connection->server_info) get_result() produces the following error message:
Fatal error: Call to undefined method mysqli_stmt::get_result() in X on line X (line of get_result)
The behaviour of mysqli_num_rows() depends on whether buffered or unbuffered result sets are being used. For unbuffered result sets, mysqli_num_rows() will not return the correct number of rows until all the rows in the result have been retrieved. Note that if the number of rows is greater than PHP_INT_MAX, the number will be returned as a string.
Also make sure that you declare ->store_result() first. Moreover the function doesn't work with LIMIT used jointly with SQL_CALC_FOUND_ROWS. If you want to obtain the total rows found you must do it manually.
EDIT:
If nothing from the suggestions does not work for you, then I would propose to rewrite your SQL query:
SELECT `Name`, (SELECT COUNT(*) FROM `Persons`) AS `num_rows` FROM `Persons` WHERE `Name` LIKE ?
This query will return the total number from your Persons table, as well as Name, if exist.

MySQLi multiple prepare statements

I have checked everywhere thoroughly, and have gone through everything possible to find an answer to this. Besides saying "the code doesn't work" which obviously is not enough, I have yet to find anything that will even come close to this. I'm probably going to get downvotes, but let's see how this goes.
I am learning how to do prepared statements for a search query from the user end, and I have to do it for multiple queries. I have to bind parameters to these multiple queries, and then execute them and use them and receive multiple rows. This is most of my code, and what I currently have is not reporting any errors whatsoever. It just returns a blank white page.
I am doing this from a simple test.php file, and those are the results I'm getting.
Now for the code.
$prep1 = $test->prepare("SELECT * FROM sb__bans WHERE sb__bans.authid=? ORDER BY sb__bans.bid DESC");
$prep2 = $test->prepare("SELECT * FROM sb__bans AS bans INNER JOIN sb__admins AS admins ON bans.aid = admins.aid WHERE bans.authid=? ORDER BY bans.bid DESC");
$prep3 = $test->prepare("SELECT * FROM sb__bans AS bans INNER JOIN sb__servers AS servers ON bans.sid = servers.sid WHERE bans.authid=? ORDER BY bans.bid DESC");
$search = "steam";
$prep1->bind_param("s", $search);
$prep2->bind_param("s", $search);
$prep3->bind_param("s", $search);
$prep1->execute();
$prep2->execute();
$prep3->execute();
while($row = $prep1->fetch() && $admin = $prep2->fetch() && $sv = $prep3->fetch()) {
echo $row['test'];
echo $admin['test'];
echo $sv['test'];
}
The database is initialized above this as $test = new mysqli("localhost", "test", "test", "test");
$search = "steam" steam would be replaced with the the post variable of course, but for testing reasons I've removed that for now and am testing with just a simple variable.
What seems to be the problem here?
Thanks in advance.
Regarding the general question you asked.
There is not a single problem with having multiple queries prepared. While speaking of getting results from a prepared query, there is indeed a problem caused by the result buffering. In order to be able to execute another query, you have to call store_result()/get_result() right after execute.
Regarding the particular problem you have.
To get errors you have to ask PHP for them.
There is absolutely no point in making three queries, you have to make just one. If you have a trouble making one, ask another question marking it with mysql tag and bringing your 3 queries along.
Even for multiple queries it's just wrong idea to do multiple fetches in a single loop. Fetch your query results one by one.
Your mysqli syntax even for a single query is incomplete. You need to re-read your tutorial and practice on a single query first.
Two points:
Based on personal experience, you can only have one prepared statement in existence at a time. I suspect this is because the db requires each PS to have a session-unique name, and the PHP layer is passing some common default name rather than generating a unique name for each PS. By comparison, the PostgreSQL driver allows an optional name for each PS, but still allows only one unnamed PS to exist. Essentially this means that you must prepare, bind, execute and fetch one PS completely before you can prepare the next PS.
You're misusing mysqli_stmt::fetch(). fetch() returns only true or false, and is used to update variables which have previously been bound with mysqli_stmt::bind_result(). To retrieve values into a $row array, you must first call mysqli_stmt::get_result() to return a mysqli_result, and then call mysqli_result::fetch_array().

mysqli_num_rows() expects paramter though an earlier query on the same page works

I am getting an error when querying a table in my MySQL database. It's the standard one with mysqli_num_rows when there is no value in the variable that's being passed:
Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in folder/file.php on line 29
Problem is I can't find the syntax error. I've looked at it a ton of times. Here's what my code is:
$sql_messages = "SELECT * FROM messages WHERE to='$userid'";
$result_messages = $mysqli->query($sql_messages);
$num_rows_messages = mysqli_num_rows($result_messages);
I tried a fetch array but that gave me the similar error. Nothing is getting passed into $result_messages I suppose. I echo'ed out $userid and that has a value and I've checked my database and there is a table 'messages' with a field 'to'. I'm connected to the right database because I have this code before this query:
$sql="SELECT * FROM users WHERE firstname='$firstname' && lastname='$lastname'";
$result = $mysqli->query($sql);
$row = mysqli_fetch_array($result);
And that works fine. It is the third query on the page, is there some sort of limit? Does anyone see a syntax error that I'm overlooking? Thanks, sorry if it's a small little error!
It's because $mysqli->query() returned boolean FALSE, which, according to the mysqli::query() docs, it does when an error happens. You can get more detail on the error by accessing $mysqli->errno and $mysqli->error.
I'm guessing that the root of the problem lies in the query which references a column called to, which is a MySQL reserved word. Try surrounding the word to in your query with backticks. Like this:
$sql_messages = "SELECT * FROM messages WHERE `to`='$userid'";
Really, though you should avoid naming columns and tables reserved words. Consider renaming the column if feasible.

$sql and $result - Reason for using both?

Just trying to improve the efficiency of my code so a simply question:
I see quite often people declare their SQL query using one var ($sql) and then putting the result into another ($result). Is there any reason people do this apart from keeping things slightly tidier? I presume it's slightler better just to put the SQL query straight into mysql_query(). But there may be some other reason people are hiding.
It normally to make debugging easier as you go: if something is wrong with the SQL query for any reason, you can simply print the contents of the $sql variable.
Also, the contents of SQL queries can get pretty long and it looks rather unreadable to have it inside a function call past a certain length.
Well it leads to cleaner coding if there is an error.
If you have an error on line 151 and 151 is:
mysql_fetch_array(mysql_query("SELECT * FROM something")); //where is the error
That is much harder to read then:
Error on line 150 and lines 149 - 151 are:
$sql = "SELECT * FROM something";
$result = mysql_query($sql); // ahh the error is here
mysql_fetch_array($result);
There isn't anything magical about it. Putting your SQL into a variable has a lot of upsides and very few downsides; the same cannot be said for passing your SQL query straight to the mysql_query function.
For starters... you're using mysql_query directly? Most developers are going to have wrapped such functions into some kind of database object/controller, or they're going to use PDO or the like. In any event, putting the SQL into a variable allows you to easily swap out the thing you're passing the SQL to. When I update code to switch database access methodology, it makes it easier if I am changing a line like mysql_query($sql) rather than mysql_query('SELECT .... SUPER LONG QUERY ...').
When debugging, one can simply echo($sql). If one wants to do a count query separate from the data query:
$sql = ' FROM table_name WHERE `some_field` = 1';
$count = db::getField('SELECT COUNT(`id`) '.$sql);
$page_worth = db::getRows('SELECT `id`, `name` '.$sql.' LIMIT '.$page.', '.$per_page);
And so on, and so on. It really does boil down to preference, but I find this approach much more flexible and rapidly adaptable/debuggable.

php mysql_query returns nothing after insert (and nothing is inserted either)

I've got the following code:
<?php
if(!empty($error_msg))
print("$error_msg");
else
{
require_once("../include/db.php");
$link = mysql_connect($host,$user,$pass);
if (!$link)
print('Could not connect: ' . mysql_error());
else
{
$sql = "insert into languages values(NULL,'$_POST[language]','$_POST[country_code]');";
$res = mysql_query($sql);
print("$sql<br>\n");
print_r("RES: $res");
mysql_close($link);
}
}
?>
In one word: it does not work. mysql_query doesn't return anything. If I try the same
query within php_myadmin, it works. It does not insert anything either. Also tried it as
user root, nothing either. Never had this before. Using mysql 5.1 and PHP 5.2.
Any ideas?
mysql_query will return a boolean for INSERT queries. If you var_dump $res you should see a boolean value being printed. It will return TRUE for a successful query, or FALSE on error. In no cases it ever returns NULL.
In addition, never pass input data (e.g.: $_POST) directly to an SQL query. This is a recipe for SQL injection. Use mysql_real_escape_string on it first:
$language = mysql_real_escape_string($_POST['language']);
$sql = "INSERT INTO language SET language='$language'";
And don't forget to quote your array indices (e.g.: $_POST['language'] instead of $_POST[language]) to prevent E_NOTICE errors.
You need to specify a database so the system knows which database to run the query on...
http://php.net/manual/en/function.mysql-select-db.php
Without selecting a database, your data will not be inserted
mysql_query returns a boolean for INSERT queries. If used in string context, such as echo "$res", true will be displayed as 1 and false as an empty string. A query error has possibly occured. Use mysql_error() to find out why the query has failed.
$sql = "insert into languages values(NULL,'$_POST[language]','$_POST[country_code]');";
This is very bad practise, as a malicious user can send crafted messages to your server (see SQL Injection).
You should at least escape the input. Assuming your column names are named 'language' and 'country_code', this is a better replacement for the above code:
$sql = sprintf('INSERT INTO LANGUAGES (language, country_code) VALUES ("%s","%s")',
mysql_real_escape_string($_POST['language']),
mysql_real_escape_string($_POST['country_code'])
);
For a description of the mysql_real_escape_string function, see the PHP Manual. For beginners and experienced programmers, this is still the best resource for getting information about PHP functions.
Instead of using $_POST directly, I suggest using the filter_input() function instead. It's available as of PHP 5.2.
With an INSERT query, mysql_query returns true or false according as the query succeeded or not. Here it is most likely returning false. Change the line print_r("RES: $res"); to print_r("RES: ".(int)$res); and most likely you will see it print RES: 0.
The problem may be that MySQL expects a list of column names before the VALUES keyword.
Also, you appear to be inserting POST variables directly into SQL - you should read up on SQL injection to see why this is a bad idea.
--I retract the quote comment, but still not good to directly insert $_POST values.--
Second, I don't think i've seen print_r quite used like that, try just using an echo.
And mysql_query is only expected a boolean back on an INSERT, what are you expecting?
Now ive got this:
$language = mysql_real_escape_string($_POST['language']);
$country_code = mysql_real_escape_string($_POST['country_code']);
$sql = "insert into shared_content.languages (id,language,country_code) values(NULL,$language,$country_code);";
$res = mysql_query($sql);
print("$sql<br>\n");
var_dump($res);
print(mysql_error());
mysql_close($link);
And the output:
insert into shared_content.languages (id,language,country_code) values(NULL,NETHERLANDS,NL);
bool(false) Unknown column 'NETHERLANDS' in 'field list'

Categories