-3

I'm trying to get the name and email from users table where the userid is the session['id'] which I set somewhere else. BTW, is this a good practice, putting user id in session variables?

EDIT: Upon further testing, this problem only occurs when I retrieve things from the users table, single or multiple columns. Using WHERE email/username/name/etc = other than WHERE userid = gives the same bind_param() error. But this only happens when using prepared statement. And there's no typo.

The prepared statement gives me Fatal error: Call to a member function bind_param() on a non-object. The same code (in the same php file, just below the following code) when retrieving one column works just fine.

$sessionid = $_SESSION['id'];

// Prepare
$stmt = $conn->prepare('SELECT name, email FROM users WHERE userid = ?');

// Set Parameters
$ps_userid   = $sessionid;

// Bind
$stmt->bind_param("i", $ps_userid);

// Execute
$stmt->execute();
$stmt->bind_result($mail_name, $mail_email);
$stmt->fetch();

`The code below works just fine

$data       = mysqli_query($conn, 'SELECT name, email FROM users WHERE userid='.$_SESSION["id"]);
$row        = mysqli_fetch_array($data, MYSQL_ASSOC);
$mail_name  = $row['name'];
$mail_email = $row['email'];
Álvaro González
  • 142,137
  • 41
  • 261
  • 360
J13t0u
  • 811
  • 1
  • 8
  • 19
  • Change `(?)` to just `?` Is your session started? You cannot bind to something that you haven't declared yet. – Jay Blanchard Mar 03 '16 at 16:38
  • 2
    A "500 Internal Server Error" status code (or a blank page) means that your script is throwing an error but you haven't configured PHP to display error messages. That's something you need to fix before you go further; it's impossible to code properly without the aid of error messages. Here's a [brief explanation](http://stackoverflow.com/a/5680885/13508). The error reporting thumb rule is: show in development, log in production. – Álvaro González Mar 03 '16 at 16:46
  • Have you looked at the error logs, since, as @ÁlvaroGonzález pointed out, you're not displaying errors? PHP will generally be very specific in logs about what is causing the problem. – Jay Blanchard Mar 03 '16 at 16:53
  • @JayBlanchard I just did, it gives me Fatal error: Call to a member function bind_param() on a non-object – J13t0u Mar 03 '16 at 17:08
  • That means `$stmt` is not an object, which means your query is failing. Are you sure you're connected to the database server (`$conn`)? – Jay Blanchard Mar 03 '16 at 17:15
  • @JayBlanchard Yes, the error only occurs when I select more than one column. I have another query just below this one, it retrieves just one column from a table, and it works just fine. – J13t0u Mar 03 '16 at 17:17
  • Without being able to peek into your environment it would be hard to know what this is failing at this point. Is this the first query? Has the connection been freed up? – Jay Blanchard Mar 03 '16 at 17:18
  • This php script gets called after registration which I insert data into tables. So no. And how do I free up connection? – J13t0u Mar 03 '16 at 17:22
  • You should close the connection after you have used it, then re-open for the next use. http://php.net/manual/en/mysqli.close.php – Jay Blanchard Mar 03 '16 at 17:27
  • Closing and reopening the connection, as far as I can tell, didn't make a difference. still gives me the bind_param error – J13t0u Mar 03 '16 at 17:38
  • are you sure the code is exactly the one you are trying to run? The described problems could come from a simple typo like `$stmt` and `$stm` – Kyborek Mar 03 '16 at 18:50
  • Yes, I copy pasted it straight from my file. – J13t0u Mar 03 '16 at 19:05

3 Answers3

1

This code should do better. I put in comments why the change is there.

// first test your connection is valid
if ($conn->connect_error) {
    die('Connect Error: ' . $conn->connect_error);
}
// Prepare, without parentheses around question mark. 
$stmt = $conn->prepare('SELECT name, email FROM users WHERE userid = ?')
      or die($conn->error);

// First Set Parameters(!)
$userid   = $_SESSION['id'];

// Only then: Bind
$stmt->bind_param('i', $userid);

// Execute and show error if any
$stmt->execute() or die($stmt->error);
$stmt->bind_result($mail_name, $mail_email); // needs to be this way
$stmt->fetch() or die ("no results");  // fetch is OK, but make sure you have result.

// output variables have received the result values:
echo $mail_name;
echo $mail_email;

So there are in fact the following issues:

  • The input variables need to have their values before you bind them, otherwise it comes too late
  • The output variables you bind need to be listed as separate arguments; an array is not what is expected here. Then you can address these bound output variables without further processing.
  • Parentheses around the placeholder (?) are not needed.
  • Do some error checking, displaying error messages.
trincot
  • 317,000
  • 35
  • 244
  • 286
  • 1
    if i may ask anonymous guy,-1 for what? – Kyborek Mar 03 '16 at 16:40
  • Not mine, but you left parentheses in the query which will fail. And while you did leave comments you didn't explain "why". – Jay Blanchard Mar 03 '16 at 16:42
  • Thanks for pointing that out, @JayBlanchard. Any reason why that would fail? It would be valid syntax if the values were injected in the SQL. – trincot Mar 03 '16 at 16:44
  • Parentheses around the placeholder would cause the query to fail because of syntax. Consider `WHERE userid = ('.$session['user'].')` – Jay Blanchard Mar 03 '16 at 16:46
  • That would be OK syntax if the value is numerical, which it is -- cf. the binding argument. This is valid SQL: `where userid = (21)` – trincot Mar 03 '16 at 16:46
  • I just tested with an integer using PHP7 and MySQL5.6 and got the 1064 error. – Jay Blanchard Mar 03 '16 at 16:47
  • Didn't work, the same code works in many other places, but they only retrieving one column. – J13t0u Mar 03 '16 at 16:48
  • Thanks for testing, @JayBlanchard! It leaves me a bit unsatisfied with the way MySql deals with this then. – trincot Mar 03 '16 at 16:50
  • @J13t0u, could you explain what you mean with *Didn't work*. What is the error, and on which line? – trincot Mar 03 '16 at 16:51
  • Yeah @trincot, when I first saw the question I based my comment on what I had seen just recently and was glad for a retest. Could be something odd in my setup, but I don't think it is. – Jay Blanchard Mar 03 '16 at 16:52
  • I followed the provided code, set the parameters first, then $stmt->bind_result($mail_name, $mail_email); still gives me 500 error – J13t0u Mar 03 '16 at 16:53
  • @J13t0u, I have added in my answer two occurrences of `die`. Could you add them? That way you should see better what goes wrong... The error on that line probably means the statement did not execute correctly (syntax error?) – trincot Mar 03 '16 at 16:55
  • I turned on error log, this is what it gives me: Fatal error: Call to a member function bind_param() on a non-object, but I did set $_SESSION['id'] to a variable, and then set $ps_userid to that variable before binding. – J13t0u Mar 03 '16 at 16:59
  • Please see update of my answer at start of the code. Added two more `die` statements. It might be that your connection is invalid. – trincot Mar 03 '16 at 17:07
  • @trincot I just tried it. Just gives me the error of: Fatal error: Call to a member function bind_param() on a non-object – J13t0u Mar 03 '16 at 17:09
  • Are you sure you added the `or die` also after the `$stmt = $conn->prepare ...` statement? Make sure that they are combined in one statement, so no semicolon between them. Also if that was OK, then please open phpAdmin and try that SQL statement, like `SELECT name, email FROM users WHERE userid = 1` to make sure it runs. – trincot Mar 03 '16 at 17:11
  • @trincot yes, I did, only gives me the bind_param error. Connection is just fine, I have another query just below this one, it retrieves just one column, and it works just fine. Also, if I don't use prepared statement, it works. – J13t0u Mar 03 '16 at 17:13
  • This is very strange, because your error means *$stmt* is FALSE. You can var_dump it (`var_dump($stmt);`) to verify that indeed this is the case. And if it is FALSE, the `die` should have been executed. Can you add that var_dump right after the prepare statement and tell me what you get? – trincot Mar 03 '16 at 17:16
  • That gives me this `object(mysqli_stmt)#2 (10) { ["affected_rows"]=> int(0) ["insert_id"]=> int(0) ["num_rows"]=> int(0) ["param_count"]=> int(1) ["field_count"]=> int(2) ["errno"]=> int(0) ["error"]=> string(0) "" ["error_list"]=> array(0) { } ["sqlstate"]=> string(5) "00000" ["id"]=> int(5) }` – J13t0u Mar 03 '16 at 17:19
  • OK, that is a valid statement object. So now it really is strange why the *bind_param* method is saying it is not an object. Is there anything else you do in your code between the *prepare* call and the *bind_param* call? If you move the var_dump right before the *bind_param* call, do you still get the same output? – trincot Mar 03 '16 at 17:22
  • Other than setting the parameters, no. And yes, var_dump before bind_param gives me the same thing. – J13t0u Mar 03 '16 at 17:24
  • Ok, could you `var_dump($userid);` as well to make sure it is a simple integer and not another data type? I need to be off-line now for at least 2 hours, but I will certainly check later again. – trincot Mar 03 '16 at 17:28
  • it's int(10), in my database, the userid has a type of int(11), does that make any difference? The $_SESSION['id'] is set when the user registers and his/her data is inserted into the users table and the userid is primary key and auto increment. And `$_SESSION['id'] = mysqli_insert_id($conn);` So they should be the same? – J13t0u Mar 03 '16 at 17:41
  • That all seems right: *int(11)* means it is value 11, while the *int(10)* in your database means the field is an *int*. So: we have a valid statement object, a valid integer, yet *bind_param* gives an error. Are you sure the error is on that line and not on another line? Could you put `echo 'test 1';` before and `echo 'test 2';` right after the call to *bind_param* and see that the error occurs after `test 1`, and you don't get to see the `test 2`? – trincot Mar 03 '16 at 19:05
  • @trincot Thanks for helping me man! Kyborek solved it, I need to close my prepared statements. I didn't know I needed to do that. – J13t0u Mar 03 '16 at 19:12
  • Good to hear you got it solved. And I will remember to put that on my check-list next time :) – trincot Mar 03 '16 at 19:14
1

I am almost sure the problem is in this code:

// Bind
$stmt->bind_param('i', $userid);
// Set Parameters
$userid   = $_SESSION['id'];

You can't bind undefined variable because bind_param takes a reference to it and there can not be reference to undefined variable, just swap the lines.

// Set Parameters
$userid   = $_SESSION['id'];
// Bind
$stmt->bind_param('i', $userid);

also your comment is right about binding result, use $stmt->bind_result($mail_name, $mail_email);

If you are new to mysqli documentation on php.net is your great friend. Just scroll down to some examples

Kyborek
  • 1,519
  • 11
  • 20
  • Didn't work, the same code works in many other places, but they only retrieving one column. – J13t0u Mar 03 '16 at 16:47
  • If you want to retrieve multiple columns just use the `bind_result` with multiple values, again one example for all: http://php.net/manual/en/mysqli-stmt.bind-result.php#refsect1-mysqli-stmt.bind-result-examples Maybe this is not the first statement called on a page and you are missing `$stmt->close()` call? – Kyborek Mar 03 '16 at 16:50
  • Yeah I tried that, still give me 500 internal error – J13t0u Mar 03 '16 at 16:51
  • If that is the case try turning error reporting on and also try to output `$mysqli_stmt->error` after each statement command (prepare,execute, fetch, ...) – Kyborek Mar 03 '16 at 16:53
  • Ok, I'll try that. Never done that before. – J13t0u Mar 03 '16 at 16:54
  • it gives Fatal error: Call to a member function bind_param() on a non-object. – J13t0u Mar 03 '16 at 16:57
  • if you cannot call bind_param() on a non-object it means `$stmt` is false and it means query preparation has failed. I have to repeat myself: do you call any prepared queries before the one in your question? If so do you close the prepared statements? Otherwise post your full code because the problem seems to be elsewhere. It means something is wrong with database connection – Kyborek Mar 03 '16 at 18:48
  • Oh! I didn't know I need to close the prepared statements. Problem solved! – J13t0u Mar 03 '16 at 19:10
0

Try assigning $userid value before binding the param, set then bind

// Set Parameters
$userid   = $_SESSION['id'];

// Bind
$stmt->bind_param('i', $userid);
Jay Blanchard
  • 34,243
  • 16
  • 77
  • 119
kraiosis
  • 46
  • 1
  • Didn't work, the same code works in many other places, but they only retrieving one column. – J13t0u Mar 03 '16 at 16:47