I am using a Microsoft Access Database and am connected to it by ODBC in my PHP code. I have looked online and the PHP manual says that odbc_exec prepares and executes the statement.
My code has parameters to avoid an sql injection but I cannot use odbc_prepare and odbc_execute as they are not supported by MS Access. I am having trouble finding out how to bind my variables to the parameters in my sql statement.
PHP
<?php
$con=odbc_connect("InventoryDB", "", "");
if (isset($_POST['partNumber'])) {
$partNum = $_POST['partNumber'];
}
if (isset($_POST['manufacturer'])) {
$manufacturer = $_POST['manufacturer'];
}
if (isset($_POST['supplier'])) {
$supplier = $_POST['supplier'];
}
if (isset($_POST['catalogNumber'])) {
$catalogNumber = $_POST['catalogNumber'];
}
if (isset($_POST['deviceFamily'])) {
$deviceFamily = $_POST['deviceFamily'];
}
if (isset($_POST['listPrice'])) {
$listPrice = $_POST['listPrice'];
}
if (isset($_POST['quantity'])) {
$quantity = $_POST['quantity'];
}
if (isset($_POST['packets'])) {
$packets = $_POST['packets'];
}
$stmt = odbc_prepare($con, 'INSERT INTO Parts (PartNumber, Manufacturer, Supplier, CatalogNumber, DeviceFamily, ListPrice, Quantity, Packets) VALUES (?, ?, ?, ?, ?, ?, ?, ?)'); // Insert all of the values from the form into the table
$rs = odbc_execute($stmt, array($partNum, $manufacturer, $supplier, $catalogNumber, $deviceFamily, $listPrice, $quantity, $packets));
?>
I would like to know how to do what I am currently doing with prepare and execute using just odbc_exec.
The values all come from a form to add to the database which shows the inventory of a company.
EDIT
The error that using prepare and execute returns is odbc_prepare():
SQL error: [Microsoft][ODBC Driver Manager] Driver does not support this
function, SQL state IM001 in SQLDescribeParameter
Consider PHP's generalized DB-API, PDO, that among other RBDMS's can connect to MS Access via ODBC for parameterized queries. You may need to enable php_pdo_odbc in .ini file:
$database = "C:\\path\\to\\mydatabase.accdb";
// WITH DSN
$dbh = new PDO("odbc:DSN=MS Access Database;DBq=$database;");
// WITH DRIVER
// $dbh = new PDO("odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBq=$database;");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "INSERT INTO Parts (PartNumber, Manufacturer, Supplier, CatalogNumber,
DeviceFamily, ListPrice, Quantity, Packets)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
try {
$sth = $dbh->prepare($sql);
$sth->execute(array($partNum, $manufacturer, $supplier, $catalogNumber,
$deviceFamily, $listPrice, $quantity, $packets));
}
catch(PDOException $e) {
echo $e->getMessage()."\n";
}
// CLOSE CONNECTION
$dbh = null;
If you can't use odbc_prepare you have to generate your SQL statement as a string and do the best you can to defend against SQL injection. By far the biggest problem is the ' character. I use these two functions:
function Qs($Text) { return(str_replace("'","''",$Text)); }
function Qsz($Text) { return(empty($Text)?'NULL':("'".Qs($Text)."'")); }
The first just avoids issues with '. I use the second if I want to insert NULL instead of an empty string (usually the case).
Use double quotes on generating your SQL statement, so they don't conflict with the single quotes inside the statement. Example (assuming both fields are text):
$sql = "INSERT INTO Parts (PartNumber, Manufacturer) VALUES (".Qsz($_POST['partNumber']).",".Qsz($_POST['partNumber']).")";
Related
I have try to use ODBC to insert data. However, it does not work
This is my code. How can I solve the problem?
<?php
if(isset($_POST['submit']))
{ $ContactPersonID=$_POST['ContactPersonID']
$FirstName=$_POST['First name'];
$LastName=$_POST['Last name'];
$PhoneNumber=$_POST['PhoneNumber'];
$RestaurantID=$_POST['RestaurantID'];
echo $ContactPersonID ." ".$FirstName." ".$LastName." ".$PhoneNumber." ".$PhoneNumber." ".$RestaurantID ;
$con=odbc_connect("Online Food Delivery Database","", "");
$sql="INSERT INTO RestaurantPeopleContact
(ContactPersonID,FirstName,LastName,PhoneNumber,RestaurantID)
VALUES ('$ContactPersonID','$FirstName','$LastName','$FirstName','$PhoneNumber','$RestaurantID')";
if(odbc_exec($con,$sql))
{
echo "Data saved.";
}
else
{
echo "Error";
}
}
?>
You are inserting twice the firstname.
By this reason, the columns declaration doesnt match with the number of variables
Consider using PHP's PDO for the MS Access connection, a better handler to pass parameters and raise needed exceptions and of course to avoid SQL injection especially from web input. You may need to initialize PDO in your .ini file.
Also, ContactPersonID and RestaurantID might be integer values but you look to be quoting them. Parameters help in defining needed data types without worrying about quote enclosures or messy string concatenation.
$ContactPersonID = $_POST['ContactPersonID']
$FirstName = $_POST['First name'];
$LastName = $_POST['Last name'];
$PhoneNumber = $_POST['PhoneNumber'];
$RestaurantID = $_POST['RestaurantID'];
$database = "C:\Path\To\Database\Online Food Delivery Database.accdb";
# PREPARED STATEMENT WITH PLACEHOLDERS
$sql = "INSERT INTO RestaurantPeopleContact
(ContactPersonID, FirstName, LastName, PhoneNumber, RestaurantID)
VALUES (?, ?, ?, ?, ?)";
try {
$dbh = new PDO("odbc:DSN=MS Access Database;DBq=$database;");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sth = $dbh->prepare($sql);
# BIND PARAMETERS
$sth->bindParam(1, $ContactPersonID, PDO::PARAM_INT);
$sth->bindParam(2, $FirstName, PDO::PARAM_STR);
$sth->bindParam(3, $LastName, PDO::PARAM_STR);
$sth->bindParam(4, $PhoneNumber, PDO::PARAM_STR);
$sth->bindParam(5, $RestaurantID, PDO::PARAM_INT);
$sth->execute();
}
catch(PDOException $e) {
echo $e->getMessage()."\n";
}
# close the connection
$dbh = null;
When i var_dump($q), I can see the records that is to be inserted into the mysql database, but when I try to do this $result = mysqli_query($con,$q);, the system is not returning an error message neither is the record inserted.
<?php
$con = #mysqli_connect("localhost", "root", "", "troubleshoot_db") or
die(mysqli_error("Couldn't Establish a Connection"));
if( isset($_POST['submit']) )
{
$Grade = $_POST['Grade'];
foreach( $Grade as $key => $v )
{
$fault_code = $key;
$q = sprintf( 'INSERT INTO `history_tb` VALUES ("%s", "%s", "%s", "%s", "%s")', $v['troubleshoot_type'] , $v['troubleshoot_result'], $v['possible_solution'], $v['reg_id'], $v['date']);
//var_dump($q);
$result = mysqli_query($con,$q);
}
}
?>
INSERT INTO table (a,b) VALUES (1,2), (2,3), (3,4);
$query = "INSERT INTO table_name( name, address) VALUES ('jony', 'test1'),('bob', 'test2')";
mysql_query($query);
There are two things to tackle before anything else.
Using prepared statements
Since we are using prepared statements, make use of this functionality for inserting multiple values.
Change your code into the following (only amended inside the if statement):
<?php
$con = #mysqli_connect("localhost", "root", "", "troubleshoot_db") or
die(mysqli_error("Couldn't Establish a Connection"));
if( isset($_POST['submit']) )
{
$Grade = $_POST['Grade'];
$stmt = $mysqli->prepare("INSERT INTO `history_tb` VALUES (?, ?, ?, ?, ?)"); //Prepare the sql command
foreach ($Grade as $key => $v )
{
// Assuming all are strings for now
$stmt->bind_param("sssss", $v['troubleshoot_type'] , $v['troubleshoot_result'], $v['possible_solution'], $v['reg_id'], $v['date']); // Bind the values in order to the ?'s
$stmt->execute(); // Execute the completed sql command
}
$stmt->close(); // Close the database connection
}
?>
What we are doing here is saying my SQL is
INSERT INTO `history_tb` VALUES (?, ?, ?, ?, ?)`
now loop through your array and call this SQL with the parameters given at each section of the loop.
This solves the first two issues of not using prepared statements and looping when using prepared statements.
Try this and lets see if records get inserted
I'd also check that the foreach is correct, maybe it needs to be
foreach ($Grade as $v)
but without seeing the data I can't confirm.
You can also take this further to add error handling:
if ($stmt = $mysqli->prepare("INSERT INTO `history_tb` VALUES (?, ?, ?, ?, ?)"))
{
foreach ($Grade as $key => $v )
{
// Assuming all are strings for now
// Bind the values in order to the ?'s or log error
if(!$stmt->bind_param("sssss", $v['troubleshoot_type'] , $v['troubleshoot_result'], $v['possible_solution'], $v['reg_id'], $v['date']))
{
die('bind_param() failed: ' . htmlspecialchars($stmt->error));
}
// Execute the completed sql command or log error
if (!$stmt->execute())
{
die('execute() failed: ' . htmlspecialchars($stmt->error));
}
}
$stmt->close(); // Close the database connection
}
else
{
die('prepare() failed: ' . htmlspecialchars($con->error));
}
Edit: added error handling
I'm trying to figure out how to use sql transactions with mysqli prepared statements. I haven't been able to find any examples that use multiple prepared statements (that aren't OO), so I'm not really sure how to use transactions with them.
This is the closest I could figure:
mysqli_autocommit($database, FALSE);
$transferq = 'INSERT INTO money (user_id, bank, onhand, type, amount, source) VALUES (?, ?, ?, ?, ?, ?)';
$transferstmt = mysqli_stmt_init($database);
mysqli_stmt_prepare($transferstmt, $transferq);
mysqli_stmt_bind_param($transferstmt, 'iiisis', $userid, $newbank, $newmoney, $type, $amount, $source);
mysqli_stmt_execute($transferstmt);
$insertq = 'UPDATE users SET money=?, bank=? WHERE user_id=' . $userid . ' LIMIT 1';
$insertstmt = mysqli_stmt_init($database);
mysqli_stmt_prepare($insertstmt, $insertq);
mysqli_stmt_bind_param($insertstmt, 'ii', $newmoney, $newbank);
mysqli_stmt_execute($insertstmt);
mysqli_commit($database);
But, I have no idea if that would even work. My biggest issue, though, is I'm not sure how to check if the queries failed or not (and therefore whether or not to commit). I saw an example that I think did something like
if(mysqli_stmt_execute($stmt)){
mysqli_commit($database);
}else{
mysqli_rollback($database);
}
But I can't really do that since I have multiple prepared statements to execute.
How is this supposed to work?
Maybe I did not understand your question, but what about this?
mysqli_autocommit($database, FALSE);
$transferq = 'INSERT INTO money (user_id, bank, onhand, type, amount, source) VALUES (?, ?, ?, ?, ?, ?)';
$transferstmt = mysqli_stmt_init($database);
mysqli_stmt_prepare($transferstmt, $transferq);
mysqli_stmt_bind_param($transferstmt, 'iiisis', $userid, $newbank, $newmoney, $type, $amount, $source);
if (not mysqli_stmt_execute($transferstmt) ){
mysqli_rollback($database);
return;
}
$insertq = 'UPDATE users SET money=?, bank=? WHERE user_id=' . $userid . ' LIMIT 1';
$insertstmt = mysqli_stmt_init($database);
mysqli_stmt_prepare($insertstmt, $insertq);
mysqli_stmt_bind_param($insertstmt, 'ii', $newmoney, $newbank);
if (not mysqli_stmt_execute($insertstmt) ){
mysqli_rollback($database);
return;
}
mysqli_commit($database);
The next level if form of this object-oriented using of mysqli or PDO (without transactions, as example of way of work with database):
class my_database{
private static $inner_link_to_driver;
protected static function factory( ){
if (not static::$inner_link_to_driver){
static::$inner_link_to_driver = new ...(USER, SERVER, PASSWD, PORT);
}
return static::$inner_link_to_driver;
}
public static function do_something($params, &$message ){
$query = "...";
$stmt = static::factory()->prepare($query);
if (not $stmp ){
$message = 'Error prepare query '.$query.PHP_EOL.static::factory()-> ..(get_error);
return FALSE;
}
if (not $stmt->execute($params) ){
$message = 'Error execute query '.$query.PHP_EOL.static::factory()-> ..(get_error);
return FALSE;
}
return TRUE;
}
}
I was wondering if someone could help me.
Im trying to integrate some code into my application, the code that i need to integrate is written with PDO statements and i have no idea how it goes.
I was wondering if someone could help me convert it.
The code is as follows
$sql = "insert into message2 (mid, seq, created_on_ip, created_by, body) values (?, ?, ?, ?, ?)";
$args = array($mid, $seq, '1.2.2.1', $currentUser, $body);
$stmt = $PDO->prepare($sql);
$stmt->execute($args);
if (empty($mid)) {
$mid = $PDO->lastInsertId();
}
$insertSql = "insert into message2_recips values ";
$holders = array();
$params = array();
foreach ($rows as $row) {
$holders[] = "(?, ?, ?, ?)";
$params[] = $mid;
$params[] = $seq;
$params[] = $row['uid'];
$params[] = $row['uid'] == $currentUser ? 'A' : 'N';
}
$insertSql .= implode(',', $holders);
$stmt = $PDO->prepare($insertSql);
$stmt->execute($params);
You shoudl use PDO unles for some technical reason you cant. If you dont know it, learn it. Maybe this will get you started:
/*
This the actual SQL query the "?" will be replaced with the values, and escaped accordingly
- ie. you dont need to use the equiv of mysql_real_escape_string - its going to do it
autmatically
*/
$sql = "insert into message2 (mid, seq, created_on_ip, created_by, body) values (?, ?, ?, ?, ?)";
// these are the values that will replace the ?
$args = array($mid, $seq, '1.2.2.1', $currentUser, $body);
// create a prepared statement object
$stmt = $PDO->prepare($sql);
// execute the statement with $args passed in to be used in place of the ?
// so the final query looks something like:
// insert into message2 (mid, seq, created_on_ip, created_by, body) values ($mid, $seq, 1.2.2.1, $currentUser, $body)
$stmt->execute($args);
if (empty($mid)) {
// $mid id is the value of the primary key for the last insert
$mid = $PDO->lastInsertId();
}
// create the first part of another query
$insertSql = "insert into message2_recips values ";
// an array for placeholders - ie. ? in the unprepared sql string
$holders = array();
// array for the params we will pass in as values to be substituted for the ?
$params = array();
// im not sure what the $rows are, but it looks like what we will do is loop
// over a recordset of related rows and do additional inserts based upon them
foreach ($rows as $row) {
// add a place holder string for this row
$holders[] = "(?, ?, ?, ?)";
// assign params
$params[] = $mid;
$params[] = $seq;
$params[] = $row['uid'];
$params[] = $row['uid'] == $currentUser ? 'A' : 'N';
}
// modify the query string to have additional place holders
// so if we have 3 rows the query will look like this:
// insert into message2_recips values (?, ?, ?, ?),(?, ?, ?, ?),(?, ?, ?, ?)
$insertSql .= implode(',', $holders);
// create a prepared statment
$stmt = $PDO->prepare($insertSql);
// execute the statement with the params
$stmt->execute($params);
PDO really is better. It has the same functionality as MySQLi but with a consistent interface across DB drivers (ie. as long as your SQL is compliant with a different database you can theoretically use the exact same php code with mysql, sqlite, postresql, etc.) AND much better parameter binding for prepared statements. Since you shouldnt be using the mysql extension any way, and MySQLi is more cumbersome to work with than PDO its really a no-brainer unless you specifically have to support an older version of PHP.
So this is my current code:
function addPage($uniquename, $ordernum, $title, $author, $content, $privilege, $description=NULL, $keywords=NULL){
if (!$description) $description = NULL;
if (!$keywords) $keywords = NULL;
//UPDATE `table` SET `ordernum` = `ordernum` + 1 WHERE `ordernum` >= 2
$query = "UPDATE ".$this->prefix."page SET ordernum = ordernum+1 WHERE ordernum >= ?";
if ($stmt = $this->db->prepare($query)){
$stmt->bind_param("i", $ordernum);
$stmt->execute();
if (!arCheck($stmt)) return false;
} else {
$this->stmtError("addPage", $stmt->error);
}
$query = "INSERT INTO ".$this->prefix."page VALUES (LCASE(?), ?, ?, ?, ?, ?, ?, ?)";
if ($stmt = $this->db->prepare($query)){
$stmt->bind_param("sisisssi", $uniquename, $ordernum, $title, $author, $content, $description, $keywords, $privilege);
$stmt->execute();
return arCheck($stmt);
} else {
$this->stmtError("addPage", $stmt->error);
}
}
It is suppose to add a new page to the datatable. The MySQL is courtesy of Phil Hunt from Store the order of something in MySQL
I know that you can use multiquery to accomplish the same thing, however I was told that prepared statement is better in performance, and security. Is there another way to do this? Like a prepared multi query?
Also, what about doing Transactions? I'm not fully sure of what that is, I assume that it's if, let's say, the INSERT statement fails, it will undo the UPDATE statement as well?
NOTE: the arCheck function will close the statement.
Prepared statements are indeed faster for repeated queries, at least in most cases. They're also safer because they automatically escape input values, preventing SQL injection attacks. If you want to use them in PHP you'll need the MySQLi extension.
You appear to have the right idea about transactions. With MySQLi there are commit and rollback methods, otherwise you can use mysql_query("COMMIT") or mysql_query("ROLLBACK").