Trying to get a grasp of using PDO, and I'm using some pre-made functions to make things simpler for when I want to do a query. First one connects, second runs the query.
Unfortunately it won't let me INSERT rows using dbquery(). SELECT works fine, just can't seem to get anything else to work.
Here's the code:
function dbConnect()
{
global $dbh;
$dbInfo['database_target'] = "localhost";
$dbInfo['database_name'] = "mysqltester";
$dbInfo['username'] = "root";
$dbInfo['password'] = "password";
$dbConnString = "mysql:host=" . $dbInfo['database_target'] . "; dbname=" . $dbInfo['database_name'];
$dbh = new PDO($dbConnString, $dbInfo['username'], $dbInfo['password']);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$error = $dbh->errorInfo();
if($error[0] != "")
{
print "<p>DATABASE CONNECTION ERROR:</p>";
print_r($error);
}
}
function dbQuery($queryString)
{
global $dbh;
$query = $dbh->query($queryString);
$i = 0;
foreach ($query as $query2)
{
$queryReturn[$i] = $query2;
$i++;
}
if($i > 1)
{
return $queryReturn;
}
else
{
return $queryReturn[0];
}
}
PDO::query Only works with queries that return a result set (e.g. SELECT)
For INSERT/UPDATE/DELETE see PDO::exec
If you are going to be inserting user provided data into your DBMS I strongly suggest using the prepared statement functionality of PDO to provide automatic escaping to prevent SQL injection.
e.g.
<?php
$stmt = $dbh->prepare("INSERT INTO tester1 (name, age) VALUES (?, ?)");
$stmt->execute(array('James',25));
See PDO::prepare and PDOStatement::execute
Related
Just changed my previous question to reflect PDO changes everyone told me to make. Am I doing this right? Error reporting right? Is everything secure?
Just changed my previous question to reflect PDO changes everyone told me to make. Am I doing this right? Error reporting right? Is everything secure?
try{
$connection = new PDO('mysql:host=supertopsecret;dbname=supertopsecret;charset=utf8mb4',
'supertopsecret', 'supertopsecret');
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
//Query 1 - Insert Provider's Name
//if(isset($_POST['submit'])){ delete this? do I still use this? halp
$stmt1 = $connection->prepare("INSERT INTO
`providers`(provider_first_name,provider_last_name,date_added)
VALUES (:providerfirstname, :providerlastname, NOW())");
//bind parameters:
$stmt1->bindParam(':providerfirstname', $providerfirstname);
$stmt1->bindParam(':providerlastname', $providerlastname);
//insert row
$providerfirstname = $_POST['providerfirstname'];
$providerlastname = $_POST['providerlastname'];
$stmt1->execute();
//Query 2 - Insert Practices
$prov_id = $connection->lastInsertId();
/*Get all values of practice_name[]:*/
$practicename = $_POST['practice_name'];
for ($i = 0; $i < count($practicename); $i++) {
if ($practicename[$i]) {
$practice_name_data = $practicename[$i];
$stmt2 = $connection->prepare("INSERT INTO
practices(prov_id,practice_name) VALUES (:prov_id,:practice_name)");
$stmt2->bindParam(':prov_id', $prov_id);
$stmt2->bindParam(':practice_name', $practice_name_data);
$stmt2->execute();
}
}
echo '<center><h3><br><br><br>Thank you! Your provider has
successfully been submitted to the database!</center></h3></br>';
} catch(PDOException $e){
echo "Sorry, there was an problem submitting your provider to the
database. Please try again or copy and paste the error code below to
the \"Report a Problem\" page and we will try to correct the problem.
</b></br></br> Error: " . $e->getMessage();
die();
}
$connection = null;
You should use prepared statements instead of escaping yourself, see How can I prevent SQL injection in PHP?. But it's probably '$practicename[$i]'. It would be '{$practicename[$i]}', but easier:
foreach($practicename as $value){
if($value!=""){
$value = mysqli_real_escape_string($connection, $value);
$query2 = mysqli_query($connection,
"INSERT INTO `practices`(prov_id,practice_name)
VALUES ('$prov_id','$value')");
}
}
But again, abandon this and use Prepared Statements!
Check this it may help you. Use PDO for insert.
$connection = new PDO("mysql:host=xxxx;dbname=xxxx;", "xxxx", "xxxx"); //database connection
for ($i = 0; $i < count($practicename); $i++) {
if ($practicename[$i]) {
$practice_name_data = $practicename[$i];
$statement = $connection->prepare('INSERT INTO practices(prov_id,practice_name) VALUES (:prov_id,:practice_name)');
$statement->bindParam(':prov_id', $prov_id);
$statement->bindParam(':practice_name', $practice_name_data);
// etc.
$statement->execute();
}
}
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 );
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"
I have a mysqli database table that is set up like so
id---email---password.
What I want to do is insert a new row of information here. This is what I've tried:
EDIT: This is how I'm connecting to the database, saving the connection in a global variable:
global $db;
$db = new mysqli( 'localhost', 'username', 'password', 'database' );
if ( $db->connect_errno > 0 ) {
die( 'Unable to connect to database [' . $db->connect_error . ']' );
}
function juice_sign_up( $email, $password, $password_confirm )
{
global $db;
$emailCheck = 'SELECT email FROM user WHERE email = $email';
if($emailCheck == 'NULL'){
$hashPass = password_hash($password);
INSERT INTO user VALUES ($email, $hashPassword);
}
This is where that function is getting the variables:
if( isset($_POST('password_confirm'))){
juice_sign_up($_POST['email'], $_POST['password'], $_POST['password_confirm']);
}
I'm very new to using MYSQL and don't fully understand the syntax yet. Any help is appreciated.
A couple of things are wrong here. You don't execute the select query (you just build the string). And the insert statement is added as if it is PHP code, but that's not how you execute statements. Also, you need to at least escape input to your insert statement, or rather even use parameter binding.
To execute the queries, you can use mysqli->query. It returns a query result object (for select queries), or true (for DML statements). It returns false in case of an error.
I address the issues in the comments in the following snippet:
function juice_sign_up( $email, $password, $password_confirm )
{
global $db;
// The line below just assigns a string to $emailCheck. You still need to execute the query.
$emailCheck = 'SELECT email FROM user WHERE email == $email';
// Try to execute it.
$queryResult = $db->query($emailCheck);
// Check if the query succeeded and if a row is found.
// For select queries an object is returned from which you can fetch the results.
if ($queryResult !== false && $queryResult->fetch_object() === false)
{
$hashPass = password_hash($password);
// Inserting should be done in a similar way. Build a query, and execute it.
$email = $db->real_escape_string($email);
$hashPassword = $db->real_escape_string($hashPassword);
// Mind the escaping of illegal characters (above) and the quotes (below).
$statement = "INSERT INTO user VALUES ('$email', '$hashPassword')";
// Note: you won't get a result object for insert statements.
$result = $db->query($statement);
// Check the value of result to see if it worked.
}
}
You can't execute a SQL query like that.
try this:
$sql = 'INSERT INTO user VALUES ($email, $hashPassword);';
$db_con = new mysqli($host, $user, $password, $database);
$result = $db_con->query($sql);
You have to "fetch" the result to get the data you want, read the documentation how to use it. :)
Try this:
function juice_sign_up( $email, $password, $password_confirm )
{
global $db;
$emailCheck = mysqli_query($db, 'SELECT email FROM user WHERE email = $email');
if($emailCheck == 'NULL'){
$hashPass = password_hash($password);
mysqli_query($db, INSERT INTO user VALUES ($email, $hashPassword));
}
i have a query that uses a few variables in mysql. The query looks something like this:
SET #var1 = 1;
SET #var2 = 2;
SELECT * FROM table WHERE table.column1=#var1
AND table.column2=#var2
AND table.colum3=#var1 * #var2;
I would like to make a prepared statement like:
$sql=' SET #var1 = ?;
SET #var2 = ?;
SELECT * FROM table WHERE table.column1=#var1
AND table.column2=#var2
AND table.colum3=#var1 * #var2;'
and then just bind two params to it. But this gives me an mysql sytax error near the SET #var1=?;
Of course, in the example, I could bind three variables and do the calculations before querying. In my real query there are more advanced calculations and I would need to bind the same variable to multiple places. And that seems like repeating and bad coding practice.
Any solutions for this?
PHP offers prepared statements and parametrized queries out of the box, you can just use them.
$var1 = 1;
$var2 = 2;
$connection = new PDO($dsn, $user, $password);
$sql = 'SELECT * FROM table WHERE table.column1=:var1 AND table.column2=:var2 AND table.colum3=:varSum';
$statement = $connection->prepare($sql);
$statement->bindValue(':var1', $var1, PDO::PARAM_INT);
$statement->bindValue(':var2', $var2, PDO::PARAM_INT);
$statement->bindValue(':varSum', $var1 + $var2, PDO::PARAM_INT);
$statement->execute();
This code is just an example, it is not tested.
you should use multi_query
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql=' SET #var1 = '.$v1.';
SET #var2 = '.$v2.';
SELECT * FROM table WHERE table.column1=#var1
AND table.column2=#var2
AND table.colum3=#var1 * #var2;'
if ($conn->multi_query($sql) === TRUE) {
echo "New records created successfully";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
$conn->close();
?>
Here's an alternative solution: feed your values in to a subquery, then you can reference them from there:
function GetStuffFromTable(mysqli $db, int $column1, int $column2): array
{
$sql = '
SELECT *
FROM (SELECT ? var1, ? var2) vars
INNER JOIN table
ON table.column1 = vars.var1
AND table.column2 = vars.var2
AND table.column3 = vars.var1 * vars.var2;
';
$statement = $db->prepare($sql);
try
{
$statement->bind_param("ii", $column1, $column2);
$statement->execute();
$result = $stmt->get_result();
return $statement->fetch_all($result);
} finally {
$statement->close();
}
}
Note: I came here looking for an answer to the same question / I don't know PHP well, so can't comment on the quality of this solution from a PHP perspective.