I am having trouble with this query. This query results in the following error.
PDOException: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound
$sql = "INSERT IGNORE table SET user_id = :uid";
if ($con = $connection->prepare($sql)) {
$con->bindValue(':uid', intval($this->uid), PDO::PARAM_INT);
$con->debugDumpParams();
$con->execute();
}
Parameters
Params: 1
Key: Name: [4] :uid
paramno=-1
name=[4] ":uid"
is_param=1
param_type=1
Query That works.
$sql = "INSERT IGNORE table SET user_id = :uid";
if ($con = $connection->prepare($sql)) {
$con->execute([':uid' => intval($this->uid)]);
}
Question Why can't I bind any parameter or value to the PDO prepared statement?
I am using Drupal 8 and I believe that their connections replace the PDO default driver.
Drupal 8 replaces the default PDO driver with a custom driver that Drupal uses to insert, update, prepare statements, ect... These drivers override the default operations. So if you want a complete customize query you will need to set up your own connection separate from Drupal and use that.
$dsn = 'mysql:host=localhost;dbname=drupal';
$username = 'username';
$password = 'password';
$connection = new PDO($dsn, $username, $password);
Then using the custom queries will work. and you won't get the no parameters were bound error
Related
I'm using PDO with ODBC from PHP7.4 to SQLServer 12 with this Connection String:
$conn = new PDO('odbc:DRIVER={SQL Server};SERVER=MyServer,1433;Database=MyDatabase;', 'MyUser', 'MyPass');
A regular query with an Integer parameter returns data:
$SQL = <<<EOL
Select
[10-Digit Groups].[Area Code],
[10-Digit Groups].[Group]
From
[10-Digit Groups]
Where
[10-Digit Groups].[Area Code] = ?
EOL;
$stmt = $conn->prepare($SQL);
$ac1 = 602;
$success = $stmt->bindParam(1, $ac1);
$success = $stmt->execute();
foreach($stmt as $row){
var_dump($row);
}
So I add a subquery (Ctr1):
$SQL = <<<EOL
Select
[10-Digit Groups].[Area Code],
(Select Count(*) From [10-Digit Groups]) Ctr1,
[10-Digit Groups].[Group]
From
[10-Digit Groups]
Where
[10-Digit Groups].[Area Code] = ?
EOL;
$stmt = $conn->prepare($SQL);
$ac1 = 602;
$success = $stmt->bindParam(1, $ac1);
$success = $stmt->execute();
foreach($stmt as $row){
var_dump($row);
}
And it fails with:
//Uncaught PDOException: SQLSTATE[22018]: Invalid character value for cast specification: 206 [Microsoft][ODBC SQL Server Driver][SQL Server]Operand type clash: text is incompatible with int (SQLExecute[206] at ext\pdo_odbc\odbc_stmt.c:259)
I can perform similar queries with STRING parameters, but they fail with this error:
//Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 402 [Microsoft][ODBC SQL Server Driver][SQL Server]The data types nvarchar and text are incompatible in the equal to operator. (SQLExecute[402] at ext\pdo_odbc\odbc_stmt.c:259)
I've tried setting and unsetting these:
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
And I've tried setting the DataType in PDO:
$success = $stmt->bindParam(1, $a1, PDO::PARAM_STR); //Or PDO::PARAM_INT where appropriate
I've also hard-coded the parameter values into the SQL to ensure they work.
I've also tried passing the parameters in the 'execute' statement:
PDO->execute([602])
I've also tried converting both sides of the WHERE clause to nvarchar or int.
Everything works as normal with no subquery, but once it's there, the Prepared Statement fails.
Any suggestions to try (Driver String, Subquery Nesting Strategies, other PDO Attribute adjustments, etc.)?
I fixed this with 2 actions:
Install "ODBC Driver 11 for SQL Server" from Microsoft (search for it)
And change
DRIVER={SQL Server};
to
DRIVER={ODBC Driver 11 for SQL Server};
It caused a couple of rewrites, but for the most part was a direct replacement.
It allows for multiple parameters alongside subqueries.
All examples above work fine with this change.
P.S. This change also works for non-PDO odbc commands in PHP.
I got a numerical ID of 20 characters witch looks like 10527391670258314752, given this ID, how can I get the username associated with it?
The table looks like this:
id | name | password | balance
10527391670258314752 | Jhon | 12345 | 12.51
The username retrieved from the database should then be stored into $_SESSION['name'].
I've tried this:
$connection = mysqli_connect('localhost', 'root', '', 'user_data');
$id = '10527391670258314752';
$query = "SELECT username FROM user_data WHERE id = '$id'";
$result = mysqli_query($connection, $query);
$record = mysqli_fetch_array($id);
$_SESSION['id'] = $record;
echo $_SESSION['id'];
The output is Array() instead of the name.
That's actually a very good question that has almost no good answers on Stack Overflow.
Basically you need the following steps to perform a SELECT query using mysqli:
create a correct SQL SELECT statement and replace all variables in the query with with question marks (called placeholders or parameters)
Prepare the resulting query
Bind all variables to the previously prepared statement
Execute the statement
get the mysqli result variable from the statement.
fetch your data
The detailed explanation can be found in my article, How to run a SELECT query using Mysqli, as well a helper function to simplify the routine.
Following this plan here is your code
$sql = "SELECT * FROM users WHERE id=?"; // SQL with parameters
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $id);
$Stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$user = $result->fetch_assoc(); // fetch the data
now you can store the username in the session variable:
$_SESSION['name'] = $user['name'];
I would strongly recommend that you avoid the mysqli extension. You should use some database abstraction library instead of using the mysqli functions directly; the mysqli class is not suited to be used on its own.
If you really want to do it purely with the mysqli class, you have few options.
First, you need to open the connection properly. These 3 lines ensure you have the connection ready:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // enable error reporting
$mysqli = new mysqli('localhost', 'username', 'password', 'dbname');
$mysqli->set_charset('utf8mb4'); // always set the charset
Then you need to prepare a statement, bind the parameter and execute it.
$id = '10527391670258314752';
$stmt = $mysqli->prepare('SELECT username FROM user_data WHERE id=?');
$stmt->bind_param('s', $id);
$stmt->execute();
Once the statement is executed you need to fetch the results. If you have only one variable you could simply use bind_result()
$stmt->bind_result($_SESSION['name']);
$stmt->fetch();
echo $_SESSION['name'];
However, this approach is not recommended and not very flexible. Instead it's better to fetch the whole result set and get an array containing the first row.
$result = $stmt->get_result();
$row = $result->fetch_array();
$_SESSION['name'] = $row['username'];
echo $_SESSION['name'];
As an alternative with PDO the same code would look like this:
session_start();
$pdo = new PDO("mysql:host=$host;dbname=$db;charset=$charset", $user, $pass, [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_EMULATE_PREPARES => false,
]);
$id = '10527391670258314752';
$stmt = $pdo->prepare('SELECT username FROM user_data WHERE id=?');
$stmt->execute([$id]);
$_SESSION['name'] = $stmt->fetchColumn();
echo $_SESSION['name'];
I'm trying to update a MySql database using PDO in PHP.
I need to launch 4 lines of SQL code. The last one is the SELECT statement, which should return only one integer value.
The error thrown is:
exception 'PDOException' with message 'SQLSTATE[HY000]: General error' in C:\xampp\htdocs\php\set-lesson-finished.php:22
Stack trace:
#0 C:\xampp\htdocs\php\set-lesson-finished.php(22): PDOStatement->fetchColumn()
#1 {main}
And here is the code:
try {
$db_connection = new PDO('mysql:host='. DB_HOST .';dbname='. DB_NAME . ';charset=utf8', DB_USER, DB_PASS, array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$query_save = $db_connection->prepare('
DELETE FROM unfinished_lessons WHERE bought_id = :bought_id;
INSERT INTO finished_lessons VALUES (:bought_id, :time_invested, NOW());
UPDATE users SET points = points + :points_earned WHERE id = :user_id;
SELECT points FROM users WHERE id = :user_id;
');
$query_save->bindValue(':user_id', (int)$_SESSION['user_id'], PDO::PARAM_INT);
$query_save->bindValue(':bought_id', (int)$_POST['bought_id'], PDO::PARAM_INT);
$query_save->bindValue(':time_invested', (int)$_POST['time_invested'], PDO::PARAM_INT);
$query_save->bindValue(':points_earned', (int)$_POST['points_earned'], PDO::PARAM_INT);
$query_save->execute();
echo $query_save->fetchColumn();
} catch (PDOException $e) {
echo $e;
}
This is not a single query but four queries together. You'll get four different result sets which need to be retrieved independently.
The error you're seeing is occurring because you can't call fetchColumn() on a DELETE query (it doesn't return a result set). Likewise for INSERT and UPDATE.
You could experiment with PDOStatement::nextRowSet(), but it's probably easier to run the four queries separately. If you're concerned about having an all-or-nothing update you should use a transaction with PDO::beginTransaction() and PDO::commit()
When queries gets complex you need to use a stored procedure:
DELIMITER //
CREATE PROCEDURE your_sp(IN `p_bought_id`, IN `p_time_invested`, IN `p_points_earned`, IN `p_user_id`)
BEGIN
DELETE FROM unfinished_lessons WHERE bought_id = p_bought_id;
INSERT INTO finished_lessons VALUES (p_bought_id, p_time_invested, NOW());
UPDATE users SET points = points + p_points_earned WHERE id = p_user_id;
SELECT points FROM users WHERE id = p_user_id;
END //
DELIMITER ;
You call it in one query like this:
$query_save = $db_connection->prepare('
call your_sp(:bought_id, :time_invested,:points_earned, :user_id)
');
You should use mysqli extension (and not PDO) if you absolutely want to run multiple statements at the same time.
As you can see in this Feature comparison (see the comparison table), only ext/mysqli has full support for multiple MySQL queries (and also supports all MySQL 5.1+ functionnality).
And, as Drupal's dawehner says, MySQL PDO no longer allows multiple database queries to be executed at the same time.
I've split the queries in four and everything works as expected:
$db_connection = new PDO('mysql:host='. DB_HOST .';dbname='. DB_NAME . ';charset=utf8', DB_USER, DB_PASS, array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$db_connection->beginTransaction();
$query = $db_connection->prepare('DELETE FROM planz_unfinished_lessons WHERE bought_id = :bought_id;');
$query->bindValue(':bought_id', (int)$_POST['bought_id'], PDO::PARAM_INT);
$query->execute();
$query = $db_connection->prepare('INSERT INTO planz_finished_lessons VALUES (:bought_id, :time_invested, NOW())');
$query->bindValue(':bought_id', (int)$_POST['bought_id'], PDO::PARAM_INT);
$query->bindValue(':time_invested', (int)$_POST['time_invested'], PDO::PARAM_INT);
$query->execute();
$query = $db_connection->prepare('UPDATE planz_users SET points = points + :points_earned WHERE id = :user_id');
$query->bindValue(':points_earned', (int)$_POST['points_earned'], PDO::PARAM_INT);
$query->bindValue(':user_id', (int)$_SESSION['user_id'], PDO::PARAM_INT);
$query->execute();
$query_check = $db_connection->prepare('SELECT points FROM planz_users WHERE id = :user_id');
$query_check->bindValue(':user_id', (int)$_SESSION['user_id'], PDO::PARAM_INT);
$query_check->execute();
$db_connection->commit();
$_SESSION['points'] = $query_check->fetchColumn();
echo $_SESSION['points'];
Note the use of beginTransaction and commit, as they should speed up the querying.
I am trying to use a prepared statement for a MySQL for the first time, but it is not returning any data:
$pdo = new PDO('mysql:dbname=[DBASE];host=localhost', '[USER]', '[PWORD]',
array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
$sth = $pdo->prepare('SELECT id FROM users WHERE username = "' . mysql_real_escape_string($_SESSION['myusername']) . '"');
$sth->execute();
$result = $sth->fetch(PDO::FETCH_OBJ);
$user_id = $result->id;
As is probably clear I am trying to return the user_id for a given username. Could someone let me know what I'm doing wrong. Thanks.
For what you are trying to do:
$pdo = new PDO('mysql:dbname=[DBASE];host=localhost', '[USER]', '[PWORD]',
array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
$sth = $pdo->prepare('SELECT id FROM users WHERE username = ?');
$success = $sth->execute(array($_SESSION['username']));
if ($success) {
$result = $sth->fetch(PDO::FETCH_OBJ);
$user_id = $result->id;
} else {
echo "Query failed.";
var_dump($sth->errorInfo());
}
You have to prepare a statement using either named or positional parameters. If the prepare was successful, you can then execute queries on that statement. Depending on how you bound the parameters, execute will accept different types of arguments.
If the execution of the statement was successful, you can then read results from it.
More examples in the manual:
Prepared Statements and Stored Procedures
PDO::prepare()
PDOStatement::execute()
Complete PDO Reference
I am trying to do a simple insert into MySQL. I am using mysqli using prepared statements. Below is the code:
$sql_query = "UPDATE $table SET $name = AES_ENCRYPT(?,'$key') WHERE $id_name = '$_SESSION[$id_name]'";
$stmt = $mysqli->prepare($sql_query);
$stmt->bind_param('b', $value);
$stmt->execute();
Yes, I am declaring $mysqli with a connection to the mySQL database server earlier in the code. $key is also declared earlier in the script. Below is the output into the mySQL general log file when this code is invoked:
120104 10:46:18 359 Connect root#localhost on payday-loan-leads
359 Query SELECT table_location, id_name, encrypt FROM insert_information WHERE required_field_name = 'first_name'
359 Prepare UPDATE personal_info SET first_name = AES_ENCRYPT(?,'^&IK8uBo92X04jhAHPUH(Y(8p3)&^ndlkj32') WHERE personal_id = '5282'
359 Execute UPDATE personal_info SET first_name = AES_ENCRYPT('','^&IK8uBo92X04jhAHPUH(Y(8p3)&^ndlkj32') WHERE personal_id = '5282'
359 Close stmt
359 Quit
As you can see, mySQL is preparing the INSERT query but does not capture the value of $value. When I remove the AES_ENCRYPT from the $sql_query, it works like a charm:
$stmt = $mysqli->prepare("UPDATE $table SET $name = ? WHERE $id_name = '$_SESSION[$id_name]'");
$stmt->bind_param('s', $value);
So the problem is with the AES_ENCRYPT function of mySQL. I tried moving the function into the bind_param line and this did not work. Anyone have any ideas here?
You use b (blob) for binding in the aes version, but s (string) in the non-aes version. Try s in the AES version - it shouldn't matter WHERE a paramter appears in a query, as long as it's not use for a field or table name.