Insert_id is null when used directly in next prepared statement - php

Finally getting around to learning prepared statements. I'm getting a maddening error when trying to run a pair of simple inserts:
$p_stmt = $mysqli->prepare("INSERT INTO ww_pages (page_key) VALUES (?)");
$p_stmt->bind_param('s', $page_key);
$p_stmt->execute();
$pv_stmt = $mysqli->prepare("INSERT INTO ww_page_versions (page_id, page_title, page_content, version_notes, version_timestamp) VALUES (?, ?, ?, ?, ?)");
$pv_stmt->bind_param('issss', $p_stmt->insert_id, $page_title, trim($_POST["page_content"]), trim($_POST["version_notes"]), date("Y-m-d H:i:s"));
$pv_stmt->execute();
echo $pv_stmt->error;
The echo $pv_stmt->error; gives this error: Column 'page_id' cannot be null
As I'm sure you can interpret, I'm trying to assign page_id the insert_id of the first statement. I'm 100% sure that this value is non-null, and returns an integer value. I tested it directly with this:
echo "NEW ID: ".$p_stmt->insert_id."::".is_int($p_stmt->insert_id);
The output? NEW ID: 13::1
What am I doing wrong? Why am I getting "column cannot be null" when the column isn't null? The only solutions I can find online are involving unexpectedly null values.

The solution to this problem is to save the value of the property $p_stmt->insert_id in a variable and bind that variable instead. You have to do the same for trim() and date() anyway, albeit for different reasons.
$insert_id = $p_stmt->insert_id;
$page_content = trim($_POST["page_content"]);
$version_notes = trim($_POST["version_notes"]);
$date = date("Y-m-d H:i:s");
$pv_stmt->bind_param('issss', $insert_id, $page_title, $page_content, $version_notes, $date);
As of PHP 8.1, you can also bind by value when you pass all values as an array to execute(). No temporary variables are needed.
$pv_stmt = $mysqli->prepare("INSERT INTO ww_page_versions (page_id, page_title, page_content, version_notes, version_timestamp) VALUES (?, ?, ?, ?, ?)");
$pv_stmt->execute([$p_stmt->insert_id, $page_title, trim($_POST["page_content"]), trim($_POST["version_notes"]), date("Y-m-d H:i:s")]);
Explanation of why binding insert_id doesn't work
The reason why binding mysqli_stmt::insert_id results in a value NULL becomes a little bit more clear on PHP 8.1. Since this version, PHP has added property types to most of built-in classes, even for properties that aren't true properties but are __get() calls instead. With PHP 8.1 you get the following error:
Fatal error: Uncaught Error: Cannot access uninitialized non-nullable property mysqli_stmt::$insert_id by reference
PHP claims that the property is uninitialized and you can't have a reference to an uninitialized property. You can mimick the same behaviour with this code:
class A {
public int $insert_id;
}
$a = new A();
$stmt = $mysqli->prepare('SELECT ?');
$stmt->bind_param('s', $a->insert_id);
$stmt->execute();
For the same reason, assignment by reference to a variable would not work:
$foo =& $p_stmt->insert_id;
But you might ask, how can the property be uninitialized when you can read its value without any issue. The answer is because internally these properties are implemented using function calls in PHP, similar to __get() magic method. The value is read from the internal memory of mysqlnd, not from the property itself. Properties of mysqli are just a facade to the underlying client library mysqlnd.

Put the value of insert_id into a temporary variable and bind that variable instead.
$p_stmt = $mysqli->prepare("INSERT INTO ww_pages (page_key) VALUES (?)");
$p_stmt->bind_param('s', $page_key);
$p_stmt->execute();
$insert_id = $p_stmt->insert_id;
$pv_stmt = $mysqli->prepare("INSERT INTO ww_page_versions (page_id, page_title, page_content, version_notes, version_timestamp) VALUES (?, ?, ?, ?, ?)");
$pv_stmt->bind_param('issss', $insert_id, $page_title, trim($_POST["page_content"]), trim($_POST["version_notes"]), date("Y-m-d H:i:s"));
$pv_stmt->execute();

Related

mySql and php add to database

I've been stuck on this for hours. I have to manipulate a database with a website using php. I'm trying to add data from a form to my database but it gives me :
PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in...
This is what's creating the problem.
$sqlQuery = 'INSERT INTO succursale(adresse, ouverture, fermeture, ouvert_raison) VALUES (:adresse, :ouverture, :fermeture, :ouvert_raison)';
$req = $conn->prepare($sqlQuery);
$req-> execute(array($_POST['adresse'], $_POST['ouverture'], $_POST['fermeture'], $_POST['ouvert_raison']));;
I've looked for people with a similar problem but the answers given do not match with my situation.
You are using named placeholder in your prepared statement. This means you'll need to pass those as an associative index. Otherwise the statement will not know which value to bind to the placeholder
$req-> execute(array(
':adresse' => $_POST['adresse'],
':ouverture' => $_POST['ouverture'],
':fermeture' => $_POST['fermeture'],
':ouvert_raison' => $_POST['ouvert_raison'],
));
If you don't want to do this, you can change the named placeholders to a ?
$sqlQuery = 'INSERT INTO succursale(adresse, ouverture, fermeture, ouvert_raison) VALUES (?, ?, ?, ?)';

Why is nothing written in the Sqlite3 database with this PHP code?

I usually used PDO with new PDO('sqlite:test.log'); to write in Sqlite3 databases with PHP.
Now, for a performance comparison, I'd like to try using the SQLite3 PHP class :
$db = new SQLite3('test.db');
$db->query("CREATE TABLE IF NOT EXISTS log (a, b, d);");
$stmt = $db->prepare("INSERT INTO log VALUES (?, ?, ?);");
$stmt->execute(array("a", date("Y-m-d\TH:i:sO"), 123));
Unfortunately, after this code is executed, nothing seems to be written: SELECT * from log gives no row.
What's wrong in my code?
I also tried $db->commit(); or $db->query('COMMIT;') without success.
Context: I usually use PDO, but I noticed it takes ~ 50 ms for a simple 1) open of the DB, 2) add a row, 3) commit and close. So I was curious if it was any better with Sqlite3 class instead of PDO. Result: it's the same: ~ 50 ms.
Unlike PDO, you can't provide parameters in the arguments to $stmt->execute(), you have to call $stmt->bindParam() or $stmt->bindValue().
$stmt = $db->prepare("INSERT INTO log VALUES (?, ?, ?);");
$stmt->bindValue(1, "a");
$stmt->bindValue(2, date("Y-m-d\TH:i:sO"));
$stmt->bindValue(3, 123);
$stmt->execute();
If you have an array of values, you can call bindValue() in a loop:
foreach (array("a", date("Y-m-d\TH:i:sO"), 123) AS $i => $value) {
$stmt->bindValue($i+1, $value);
}

"Object of class mysqli could not be converted to string" error in php insert

When I run this code I get the error "Object of class mysqli could not be converted to string" on the line where I declare a new mysqli object. I can't find the error no matter how many times I read it over.
if(isset($_SESSION['username']))
{
echo $_POST['course'],
$mysqli = new mysqli("localhost","sec_user","Uzg82t=u%#bNgPJw","GPA_Tracker");
$user = $_SESSION['username'];
$stmt = $mysqli->prepare("INSERT into assessment_type (username, courseID, assessment, percentage) VALUES (?, ?, ?, ?)");
$stmt->bind_param('ssss', $user, $_POST['course'], $_POST['assesment'], $_POST['percentage']);
$stmt->execute();
}
As noted in the comments, this is where you have the problem:
echo $_POST['course'], //notice the comma, rather than a semi-colon ";"
$mysqli = new mysqli("localhost","sec_user","Uzg82t=u%#bNgPJw","GPA_Tracker");
The echo statement/construct accepts a comma-separated list of statements, hence coming across the , it thinks the next statement following it is also to be echoed. As it turns out, that next statement is an object-creation statement, whereas echo accepts only strings.
To fix the error, properly close your echo $_POST['course'] with a semicolon like below:
echo $_POST['course'];

bind_param getting an error (seems illogical to me)

This doesn't seem to make sense to me. Is this ACTUALLY wrong??? I've looked at other people's work, and they have that same type of bind_param as me, like in this example:
php, mysqli-stmt.bind-param]: Number of elements in type definition string doesn't match number of bind variables
I have 23 here, AND 23 values (yes, I counted individually, even pressing enter on dreamweaver to make sure). And to be safe, I even tried with 46:
$stmt= $con->prepare("INSERT INTO form_corpo_test (compagnie, telephone, site_web, texte_fr, texte_en, categories, profil_exposant, stands_du_manufacturier, pourcentage_quebec, pourcentage_canada, pourcentage_usa, pourcentage_autre, exporte, exporte_souhaite, produits_vert, nouveau_produits, nom, courriel, telephone_ressource, personne_ressource_c_toi, autre_personne_ressource, autre_courriel, autre_telephone)
VALUES
('$_POST[company]','$_POST[phone]','$_POST[website]','$_POST[messagefr]','$_POST[messageen]','$str','$_POST[profession]','$_POST[manufacturiers_stand]','$_POST[percent_quebec]','$_POST[percent_canada]','$_POST[percent_usa]','$_POST[percent_autre]','$_POST[bt_export]','$_POST[bt_export_souhaite]','$_POST[bt_prod_verts]','$_POST[bt_new_prod]','$_POST[name]','$_POST[email]','$_POST[resource_phone]','$_POST[personne_ressource]','$_POST[backup_name]','$_POST[backup_email]','$_POST[backup_phone]')");
$stmt->bind_param("sssssssssssssssssssssss", $compagnie, $telephone, $site_web, $texte_fr, $texte_en, $categories, $profil_exposant, $stands_du_manufacturier, $pourcentage_quebec, $pourcentage_canada, $pourcentage_usa, $pourcentage_autre, $exporte, $exporte_souhaite, $produits_vert, $nouveau_produits, $nom, $courriel, $telephone_ressource, $personne_ressource_c_toi, $autre_personne_ressource, $autre_courriel, $autre_telephone);
And then I tried this (since phone numbers are integers)
sissssssiiiissssssisssi
Both outputs THIS error:
Warning: mysqli_stmt::bind_param() [mysqli-stmt.bind-param]: Number of
variables doesn't match number of parameters in prepared statement in
/home/product/public_html/sidim.com/formulaires/processForm-test.php
on line 77
EDIT 3
I have this at the moment:
$con->query("INSERT INTO form_corpo_test SELECT * FROM *");
$stmt = $con->prepare("INSERT INTO form_corpo_test VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
$stmt->bind_param('sissssssiiiissssssisssi', $compagnie, $telephone, $site_web, $texte_fr, $texte_en, $categories, $profil_exposant, $stands_du_manufacturier, $pourcentage_quebec, $pourcentage_canada, $pourcentage_usa, $pourcentage_autre, $exporte, $exporte_souhaite, $produits_vert, $nouveau_produits, $nom, $courriel, $telephone_ressource, $personne_ressource_c_toi, $autre_personne_ressource, $autre_courriel, $autre_telephone); // bind $compagnie etc. to the parameter
This still errors this outputs
Fatal error: Call to a member function bind_param() on a non-object in
/home/product/public_html/******/*******/processForm-test.php on line
83
This refers to this:
$stmt->bind_param('sissssssiiiissssssisssi', $compagnie, $telephone, $site_web, $texte_fr, $texte_en, $categories, $profil_exposant, $stands_du_manufacturier, $pourcentage_quebec, $pourcentage_canada, $pourcentage_usa, $pourcentage_autre, $exporte, $exporte_souhaite, $produits_vert, $nouveau_produits, $nom, $courriel, $telephone_ressource, $personne_ressource_c_toi, $autre_personne_ressource, $autre_courriel, $autre_telephone); // bind $compagnie etc. to the parameter
If there is anything wrong so far, lemme know by all means. I will check out u_mulder's posts more in depth now.
In php manual it is shown how to bind params:
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);
See that question marks? Every question mark will be replaced with a parameter from bind_param. So, your query should look like:
$stmt= $con->prepare("INSERT INTO form_corpo_test (compagnie,... autre_telephone) VALUES (?, ?, ?, ?, ?, ?, ?, ....."); // 26 ?-signs
$stmt->bind_param("sssssssssssssssssssssss", $compagnie, $telephone.. ); // your params here

PHP - INSERT a variable of type Time into a column in MySQL of type Time

I keep getting this error:
"Catchable fatal error: Object of class DateTime could not be converted to string"
From this code:
<?php
$value_startTime = new DateTime();
$value_startTime->setTime($value_HourStart,$_POST['TextBoxStartMin'],0);
$value_endTime = new DateTime();
$value_endTime->setTime($value_HourEnd,$_POST['TextBoxEndMin'],0);
$query_InsertJob="INSERT INTO job (jobDesc,timeStart,timeEnd)
VALUE ('$_POST[TextAreaProblem]','$value_startTime','$value_endTime')";
?>
These variables can have values from 00 to 23:
$value_HourStart
$value_HourEnd
These variables can have values from 00 to 59:
$_POST['TextBoxStartMin']
$_POST['TextBoxEndMin']
I am having no trouble with:
$_POST[TextAreaProblem]
What is it that I am doing wrong?
You need to convert those DateTime objects into strings for use in the query.
Try something like this (PDO example because I can't abide encouraging people to use the mysql_* functions)
$stmt = $db->prepare('INSERT INTO job (jobDesc, timeState, timeEnd) VALUES (?, ?, ?)');
$stmt->execute(array(
$_POST['TextAreaProblem'],
$value_startTime->format('H:i:s'),
$value_endTime->format('H:i:s')
));
$value_startTime and $value_endTime are objects. Try it with $value_startTime->getTimestamp().
$query_InsertJob="INSERT INTO job (jobDesc,timeStart,timeEnd) VALUE ('$_POST[TextAreaProblem]','".$value_startTime->getTimestamp()."','"$value_endTime->getTimestamp()."')";

Categories