Scenario:
I have a SQL Query INSERT INTO dbo.Grades (Name, Capacity, SpringPressure) VALUES ('{PHP}',{PHP}, {PHP})
The data types are correct.
I need to now get the latest IDENTIY which is GradeID.
I have tried the following after consulting MSDN and StackOverflow:
SELECT SCOPE_IDENTITY() which works in SQL Management Studio but does not in my php code. (Which is at the bottom), I have also tried to add GO in between the two 'parts' - if I can call them that - but still to no avail.
The next thing I tried, SELECT ##IDENTITY Still to no avail.
Lastly, I tried PDO::lastInsertId() which did not seem to work.
What I need it for is mapping a temporary ID I assign to the object to a new permanent ID I get back from the database to refer to when I insert an object that is depended on that newly inserted object.
Expected Results:
Just to return the newly inserted row's IDENTITY.
Current Results:
It returns it but is NULL.
[Object]
0: Object
ID: null
This piece pasted above is the result from print json_encode($newID); as shown below.
Notes,
This piece of code is running in a file called save_grades.php which is called from a ajax call. The call is working, it is just not working as expected.
As always, I am always willing to learn, please feel free to give advice and or criticize my thinking. Thanks
Code:
for ($i=0; $i < sizeof($grades); $i++) {
$grade = $grades[$i];
$oldID = $grade->GradeID;
$query = "INSERT INTO dbo.Grades (Name, Capacity, SpringPressure) VALUES ('" . $grade->Name . "',". $grade->Capacity .", ".$grade->SpringPressure .")";
try {
$sqlObject->executeNonQuery($query);
$query = "SELECT SCOPE_IDENTITY() AS ID";
$newID = $sqlObject->executeQuery($query);
print json_encode($newID);
} catch(Exception $e) {
print json_encode($e);
}
$gradesDictionary[] = $oldID => $newID;
}
EDIT #1
Here is the code for my custom wrapper. (Working with getting the lastInsertId())
class MSSQLConnection
{
private $connection;
private $statement;
public function __construct(){
$connection = null;
$statement =null;
}
public function createConnection() {
$serverName = "localhost\MSSQL2014";
$database = "{Fill In}";
$userName = "{Fill In}";
$passWord = "{Fill In}";
try {
$this->connection = new PDO( "sqlsrv:server=$serverName;Database=$database", $userName, $passWord);
$this->connection->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch( PDOException $e ) {
die("Connection Failed, please contact system administrator.");
}
if ($this->connection == null) {
die("Connection Failed, please contact system administrator.");
}
}
public function executeQuery($queryString) {
$results = array();
$this->statement = $this->connection->query( $queryString );
while ( $row = $this->statement->fetch( PDO::FETCH_ASSOC ) ){
array_push($results, $row);
}
return $results;
}
public function executeNonQuery($queryString) {
$numRows = $this->connection->exec($queryString);
}
public function getLastInsertedID() {
return $this->connection->lastInsertId();
}
public function closeConnection() {
$this->connection = null;
$this->statement = null;
}
}
This is PDO right ? better drop these custom function wrapper...
$json = array();
for ($i=0; $i < sizeof($grades); $i++) {
//Query DB
$grade = $grades[$i];
$query = "INSERT INTO dbo.Grades (Name, Capacity, SpringPressure)
VALUES (?, ?, ?)";
$stmt = $conn->prepare($query);
$success = $stmt->execute(array($grade->Name,
$grade->Capacity,
$grade->SpringPressure));
//Get Ids
$newId = $conn->lastInsertId();
$oldId = $grade->GradeID;
//build JSON
if($success){
$json[] = array('success'=> True,
'oldId'=>$oldId, 'newId'=>$newId);
}else{
$json[] = array('success'=> False,
'oldId'=>$oldId);
}
}
print json_encode($json);
Try the query in this form
"Select max(GradeID) from dbo.Grades"
Related
I have this code
<?php
class Objekt{
// database connection and table name
private $conn;
private $table_name = "objects";
// object properties
public $id;
public $id_group;
public $title;
public $description;
public $lat;
public $lng;
public $icon;
public $tagsraw;
// constructor with $db as database connection
public function __construct($db){
$this->conn = $db;
}
function create(){
// query to insert record
$query = "INSERT INTO
" . $this->table_name . "
SET
id_group=:id_group, title=:title, description=:description, lat=:lat, lng=:lng, icon=:icon;
SELECT max(id) AS id FROM objects;";
// prepare query
$stmt = $this->conn->prepare($query);
// sanitize
$this->id_group=htmlspecialchars(strip_tags($this->id_group));
$this->title=htmlspecialchars(strip_tags($this->title));
$this->description=htmlspecialchars(strip_tags($this->description));
$this->lat=htmlspecialchars(strip_tags($this->lat));
$this->lng=htmlspecialchars(strip_tags($this->lng));
$this->icon=htmlspecialchars(strip_tags($this->icon));
// bind values
$stmt->bindParam(":id_group", $this->id_group);
$stmt->bindParam(":title", $this->title);
$stmt->bindParam(":description", $this->description);
$stmt->bindParam(":lat", $this->lat);
$stmt->bindParam(":lng", $this->lng);
$stmt->bindParam(":icon", $this->icon);
// execute query
if($stmt->execute()){
//$stmt->execute();
/*
ERROR below here
Uncaught PDOException: SQLSTATE[HY000]: General error
stack trace:
#0 PDOStatement ->fetch(2)
#1 Objekt->create()
*/
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$this->id = $result['id'];
echo "$this->id";
//get tags matches
$tags = [];
$this->tagsraw = preg_replace('/\s+/', '', $this->tagsraw);
$tags = explode(',', $this->tagsraw);
$id_tags = [];
for ($i = 0; $i < sizeof($tags); $i++) {
$query = "SELECT id FROM category WHERE title=" . tags[i];
$stmt = $this->conn->prepare($query);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_OBJ);
$id_tags[i] = $result->id;
}
for ($i = 0; $i < sizeof($id_tags); $i++) {
$query = "INSERT INTO category_object SET id_object=" . $this->id . ", id_category=" . $id_tags[i];
$stmt = $this->conn->prepare($query);
$stmt->execute();
}
return true;
}
return false;
}
What I want to do:
Insert Object and create a relation to a category_object table over foreign keys id_object / id_category
What I would like to improve:
What do I have to do to delete an insert if it fails (where should I put a try/catch or something else)
What is wrong with my fetch? I Select the value from max(id) to get the value of my inserted object, why is it throwing an Exception
I have another Warning why is it telling me that
for ($i = 0; $i < sizeof($id_tags); $i++) {
$query = "INSERT INTO category_object SET id_object=" . $this->id . ", id_category=" . $id_tags[i];
$stmt = $this->conn->prepare($query);
$stmt->execute();
}
will be deprecated in future php versions..
Use transactions.
Any insert/update/delete done within a transaction will not be actually executed against the database until you call commit(), and you can always roll back the changes, abandoning them in case of failure.
In your code, you should be OK with replacing if($stmt->execute()){ with
try {
$this->conn->beginTransaction();
$stmt->execute();
// ...everything else from inside the if statement here...
$this->conn->commit();
return true;
} catch (\Exception $e) {
$this->conn->rollback();
return false;
}
Iam trying to make a OOP based forum in PHP and currently im stuck at making the Database class. Specifically Iam stuck at making a "general purpose" insert class function for the Datatable class (using PDO btw).
class DB
{
private $dbconn;
public function __construct(){
}
protected function connect($dbname, $dbhost='127.0.0.1', $dbuser='root', $dbpass=''){
try{
$this->dbconn = new PDO("mysql:host=$dbhost;dbname=$dbname;", $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
}
catch(PDOException $e){
echo 'Connection failed: '.$e->getMessage()."<br />";
}
}
protected function disconnect(){
$this->dbconn = null;
}
public function insert($dbname, ){
$this->connect($dbname);
try{
# prepare
$sql = "INSERT INTO pdodemotable (firstname, lastname, age, reg_date)
VALUES (?, ?, ?, now())";
$stmt = $dbconn->prepare($sql);
# the data we want to insert
$data = array($firstname, $lastname, $age);
# execute width array-parameter
$stmt->execute($data);
echo "New record created successfully";
}
catch(PDOException $e){
echo $sql . "<br>" . $e->getMessage();
}
}
}
The insert function is as you see unfinished. I cant figure out how to get the insert function to adapt to ANY amount of arguments, ANY amount of database columns and ANY table. The code thats in the function right now is taken from one of my other projects where I used procedural programming. Its by first time using OOP with Databases.
Im a newbie to both OOP and PDO. There must be some sort of method or function that could help me that Im missing. The only solution I see right now is to use a ridicoulus amount of string handling and if statement... it cant be the best solution... there must be a easier way...
First notice - you don't need the $dbname parameter for insert method, instead it should be a constructor parameter:
class DB {
private $dbconn;
public function __construct($dbname, $dbhost='127.0.0.1', $dbuser='root', $dbpass='') {
// also don't catch the error here, let it propagate, you will clearly see
// what happend from the original exception message
$this->dbconn = new PDO("mysql:host=$dbhost;dbname=$dbname;", $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
}
...
}
As for the insert method - first try to imagine how it will be used.
For example, it can be like this:
$db = new DB('mydb');
$db->insert('mytable', array('firstname'=>'Pete', 'lastname'=>'Smith'));
Then you can pass the table name and data (keys/values) into the method:
public function insert($table, $data) {
// again, no need to try / catch here, let the exceptions
// do their job
// handle errors only in the case you are going to fix them
// and not just to ingnore them and 'echo', this can lead to much worse problems
// see the explanation below regarding the `backtick` method
$table = $this->backtick($table);
$fields = array();
$placeholders = array();
$values = array();
foreach($data as $key=>$value) {
$fields[] = $this->backtick($key);
// you can also process some special values like 'now()' here
$placeholders[] = '?';
}
$fields = implode($fields, ','); // firstname, lastname
$placeholders = implode($placeholders, ','); // ?, ?
$sql = "INSERT INTO $table ($fields) values ($placeholders)";
$stmt = $this->dbconn->prepare($sql);
$stmt->execute(array_values($data));
}
public function update($table, $id, $data) {
$table = $this->backtick($table);
$fields = array();
foreach($data as $key=>$value) {
$fields[] = $this->backtick($key) . " = ?";
}
$fields = implode($fields, ','); // firstname=?, lastname=?
$sql = "UPDATE $table SET $fields where id=?";
$stmt = $this->dbconn->prepare($sql);
$data['id'] = $id;
$stmt->execute(array_values($data));
if ($stmt->execute(array_values($data)) === false) {
print 'Error: ' . json_encode($stmt->errorInfo()). PHP_EOL;
}
while ($row = $stmt->fetchAll()) {
print json_encode($row) . PHP_EOL;
}
}
private function backtick($key) {
return "`".str_replace("`","``",$key)."`";
}
Another alternative is to create the separate object which will represent one table row (the ActiveRecord pattern).
The code which uses such object could look like this:
$person = new Person($db);
$person->firstName = 'Pete';
$person->lastName = 'Smith';
$person->save(); // insert or update the table row
Update on possible SQL injection vulnerability
I also added the update and backtick methods to illustrate the possible SQL injection.
Without the backtick, it is possible that update will be called with something like this:
$db->updateUnsafe('users', 2, array(
"name=(SELECT'bad guy')WHERE`id`=1#"=>'',
'name'=>'user2', 'password'=>'text'));
Which will lead to the SQL statement like this:
UPDATE users SET name=(SELECT'bad guy')WHERE`id`=1# = ?,name = ?,password = ? where id=?
So instead of updating the data for user with id 2, we it will change the name for the user with id 1.
Due to backtick method, the statement above will fail with Unknown column 'name=(SELECT'bad guy')WHEREid=2#' in 'field list'.
Here is the full code of my test.
Anyway, this probably will not protect you from any possible SQL injection, so the it is much better not to use the user input for known parameters like table name and field names.
Instead of doing something like $db->insert('mytable', $_POST), do $db->insert('mytable', array('first'=>$_POST['first'])).
Try to pass the arguments has an array, then, inside the method insert, do a foreach.
Something like:
$data['first_name'] = 'your name';
...
$data['twentieth_name'] = 'twentieth name';
foreach( $data as $key => $value )
$final_array[':'.$key] = $value;
$stmt->execute( $final_array );
I have a function to search for records by course name:
<?php
function searchByCourse()
{
if (isset($_POST["course_title"])) {
//Copy to local var
$course_title = $_POST["course_title"];
$stmt = self::$conn->prepare("SELECT student_id, student_name, course_title FROM student_info WHERE course_title = ?");
$stmt->bind_param("s", $course_title);
$result = $stmt->execute();
if ($result === FALSE) {
$stmt->close();
return FALSE;
} else {
$results_array = array();
$stmt->bind_result($student_id, $student_name, $course_title_found);
while ($stmt->fetch()) {
echo "Fetch! \n";
$row = array();
$row["student_id"] = $student_id;
$row["student_name"] = $student_name;
$row["course_title"] = $course_title;
$results_array[] = $row;
}
$stmt->close();
return $results_array;
}
} else {
return FALSE;
}
}
?>
The code seems to execute fine but when I test it using curl for course_title=Computing it should return 3 results. However the echo "Fetch!" is never displayed. It seems to be that there is nothing for it to fetch. It's driving me a little crazy. I've checked all the var names in the database and they match up fine. Any ideas what I could be doing wrong here?
EDIT:
This method is part of my class DbHandler. $conn is a protected static MySqli connection object created in function__contruct().
called like this:
$db = new DbHandler();
$db->searchByCourse();
I have other database functions that work fine for this design pattern. The function is being called correctly. I have also checked the $_POST["course_title"] and that is being passed correctly.
I'm newbie in PHP and WordPress. This approach was working fine for me in ASP.NET but here both queries are not working. When I comment the first one, the second one(Insertion) is working fine.
$dbhostname="111.1.11.111";
$dbusername="db_userName";
$dbpassword="mypassword";
$con=mysqli_connect($dbhostname,$dbusername,$dbpassword,"db_name");
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
Check wether the email exists or not ?
$sql="CALL Select_ConfirmEmailExistance('abc#abc.com')";
$containsResult=0;
if ($result=mysqli_query($con,$sql))
{
// Get field information for all fields
while ($fieldinfo=mysqli_fetch_assoc($result))
{
if (isset($fieldinfo)) {
$containsResult=1;// Email Exists
}
}
mysqli_free_result($result);
if ($containsResult==0) { // In case email does not exists enter it.
$sql="CALL insert_Userinfo('abc','def','abc#abc.com','mnop')";
if ($result=mysqli_query($con,$sql))
{
$data;
while ($fieldinfo=mysqli_fetch_assoc($result))
{
$data[]=$fieldinfo;
}
}
}
print_r($data);
}
mysqli_close($con);
First Store Procdure
BEGIN
SELECT 1 as emailstatus FROM userinfo WHERE email= p_email;
END
Second Stored Procedure
INSERT INTO `userinfo` (
`first_name`,
`last_name`,
`email`,
`password`
)
VALUES
(
`FName`,
`LName`,
`Email`,
`Pass`
);
SELECT
user_id
FROM
userinfo
ORDER BY
user_id DESC
LIMIT 1;
Here is what I was talking about when I said create a query class to fetch data. This is just a simple one, but it works pretty effectively and you can build it out to be pretty powerful.
class DBEngine
{
public $con;
public function __construct($host="111.1.11.111",$db = "dbname",$user="db_userName",$pass="mypassword")
{
try {
$this->con = new PDO("mysql:host=$host;dbname=$db",$user,$pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
}
catch (Exception $e) {
return 0;
}
}
// Simple fetch and return method
public function Fetch($_sql)
{
$query = $this->con->prepare($_sql);
$query->execute();
if($query->rowCount() > 0) {
while($rows = $query->fetch(PDO::FETCH_ASSOC)) {
$array[] = $rows;
}
}
return (isset($array) && $array !== 0 && !empty($array))? $array: 0;
}
// Simple write to db method
public function Write($_sql)
{
$query = $this->con->prepare($_sql);
$query->execute();
}
}
// Create an instance of the engine
$query = new DBEngine();
// Query 1 will return an array or false (0)
$call1 = $query->Fetch("CALL Select_ConfirmEmailExistance('abc#abc.com')");
// Assign your true/false
$containsResult = ($call1 !== 0)? 1:0;
// Run second query and return array or false (0)
if($containsResult == 0)
$data = $query->Fetch("CALL insert_Userinfo('abc','def','abc#abc.com','mnop')");
// Display returned result
print_r($data);
It is quite simple. Your code is fine but you only have to create two separete functions and simply call those functions instead of the code directly.
I am trying to create a PHP array of random "fruits" from a database.
The database class that I am using:
class Db
{
private static $_instance = null;
private $_pdo;
private function __construct()
{
try {
$this->_pdo = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME .'', DB_USER, DB_PASS);
} catch (PDOException $e) {
die($e->getMessage());
}
}
public static function getInstance()
{
if (!isset(self::$_instance)) {
self::$_instance = new Db();
}
return self::$_instance;
}
public function prepare($sql)
{
return $this->_pdo->prepare($sql);
}
}
The class that is using the database to fetch "fruits" to create an array of a given size of random entries by using 3 seperate queries to calculate and retrieve "x" number of random items form the database.
class FruitBasket
{
private $_fruitArray = array(),
$_inputCode,
$_db;
public function __construct($input = null)
{
$this->_inputCode = $input;
$this->_db = Db::getInstance();
var_dump($this->_db);
}
public function pickFruit($count)
{
$doubleCount = $count * 2;//double the count used in calculation with the random number
$fruitIDs = ''; //the choosen fruits (id's)
$i = 0;
//#1 get total count of fruits table
$sql = "SELECT COUNT(*) FROM `fruits`";
if ($query = $this->_db->prepare($sql)) {
if ($query->execute()) {
$allFruits = $query->fetch(PDO::FETCH_NUM);
} else {
print_r("ERROR QUERY DID NOT EXECUTE #1");
}
} else {
print_r("ERROR CHECK SQL SYNTAX #1");
}
//#2 calculate random number to pull from all of id's
$sql = "SELECT id FROM `fruits` WHERE RAND()* ? < ? ORDER BY RAND() LIMIT 0, ? ";
if ($query = $this->_db->prepare($sql)) {
$query->bindParam(1, $allFruits[0], PDO::PARAM_INT);
$query->bindParam(2, $doubleCount, PDO::PARAM_INT);
$query->bindParam(3, $count, PDO::PARAM_INT);
if ($query->execute()) {
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
if ($i == 0) {
$fruitIDs .= "'" . $row['id'] . "'";
} else {
$fruitIDs .= ", '" . $row['id'] . "'";
}
$i++;
}
} else {
print_r("ERROR QUERY DID NOT EXECUTE #2");
}
} else {
print_r("ERROR CHECK SQL SYNTAX #2");
}
//#3 get the fruits
$sql="SELECT NAME FROM `fruits` WHERE `id` IN( ? )";
if ($query = $this->_db->prepare($sql)) {
$query->bindParam(1, $fruitIDs, PDO::PARAM_STR);
if ($query->execute()) {
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
$this->_fruitArray[] = $row['name'];
}
} else {
print_r("ERROR QUERY DID NOT EXECUTE #3");
}
} else {
print_r("ERROR CHECK SQL SYNTAX #3");
}
return $this->_fruitArray;
}
}
The table that I am attempting has a bunch of "fruits" in it, an example of how the table is structured:
==================================
| ID | NAME |
==================================
| 01 | Apple |
==================================
I am attempting to test this all out by using the following:
echo "<pre>";
echo "TESTING FRUIT ARRAY:</br></br>";
$basket = new FruitBasket();
echo"</br></br> PRINT_R: </br></br>";
print_r($basket->pickFruit(10));
echo "</br></br> VARDUMP: </br></br>";
var_dump($basket->pickFruit(10));
The sql query prepares and executes properly, I can do a vardump of the prepares and the binds and they return TRUE. Nothing is returned on the last query however.
In the first query that executes Doing a print statement of $allFruits shows the correct total count from the table.
The second query seems to be working properly,the string $fruitIDs, gets random id's from the table, I can echo this out and confirm that indeed the correct number of ID's are returned.
The problem occurs (I think) with the third query:
Nothing is returned form this query. The prepare statement returns true on a var dump as does the execute, however there is no results!
If I manually take the ID's that are output from query#2 and run it myself in mysql, the correct "fruit" names are returned.
Am I binding the variables incorrectly? I read the pages from the PHP manual but clearly I am doing something wrong.
Please help! :)
Thanks to the links and input provided by Your common sense, using the following:
Reference - frequently asked questions about PDO
and
Can I bind an array to an IN() condition?
I was able to resolve this by changing my query as follows:
//#2 calculate random number to pull from all of id's
$sql = "SELECT id FROM `fruits` WHERE RAND()* ? < ? ORDER BY RAND() LIMIT 0, ? ";
if ($query = $this->_db->prepare($sql)) {
$query->bindParam(1, $allFruits[0], PDO::PARAM_INT);
$query->bindParam(2, $doubleCount, PDO::PARAM_INT);
$query->bindParam(3, $count, PDO::PARAM_INT);
if ($query->execute()) {
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
$fruitIDs[] = $row['id'];
}
} else {
print_r("ERROR QUERY DID NOT EXECUTE #2"); }
} else {
print_r("ERROR CHECK SQL SYNTAX #2");
}
//#3 get the fruits
$inQuery = implode(',', array_fill(0, count($fruitIDs), '?'));
$sql="SELECT NAME FROM `fruits` WHERE `id` IN($inQuery)";
if ($query = $this->_db->prepare($sql)) {
if ($query->execute($fruitIDs)) {
while ($row = $query->fetch(PDO::FETCH_NUM)) {
$this->_fruitArray[] = $row[0];
}
} else {
print_r("ERROR QUERY DID NOT EXECUTE #3");
}
} else {
print_r("ERROR CHECK SQL SYNTAX #3");
}
return $this->_fruitArray;
}
I do not fully understand the security benefits or ramifications of binding the parameters or simply including them in the actual execute() but for now the query is performing as intended, so thank you for the input!