I'm trying to create a simple php object to manage a mysql database through pdo. So far it connects to the database just fine and now when I try to insert a new row i get the follow error:
PHP Fatal error: Using $this when not in object context on line 37
line 37 is $STH = $this->DBH->prepare($sql);
i'm probably just using $this wrong. any help will be appreciated.
<?
class Database {
private $DBH;
//connects to the database
function __construct($host,$dbname,$user,$pass) {
try {
$this->DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
}
catch(PDOException $e) {
echo $e->getMessage();
}
}
//inserts into the database
//$tableName name of the table to insert the info into
//$items is a multidimensional array of array(column name, value)
public function insert($tableName,$items){
$values = array();
$sql = "INSERT INTO $tableName(";
$valuePlaceHolder = ''; // holds the question marks at the end of the PDO sql string
foreach($items as $item){
$sql .= $item[0] . ',';
array_push($values, $item[1]);
$valuePlaceHolder .= '?,';
}
// remove the last comma from the sql statement
$sql = substr($sql,0,-1);
$valuePlaceHolder = substr($valuePlaceHolder, 0, -1);
$sql .= ") values ($valuePlaceHolder)";
echo $sql;
$STH = $this->DBH->prepare($sql);
$STH->execute($values);
}
}
?>
read this:
http://www.php.net/manual/es/language.oop5.basic.php#88665
So that you can solve your problem:
....
// remove the last comma from the sql statement
$sql = substr($sql,0,-1);
$valuePlaceHolder = substr($valuePlaceHolder, 0, -1);
$sql .= ") values ($valuePlaceHolder)";
echo $sql;
$STH = Database::DBH;
$SHT = $SHT->prepare($sql);
$STH->execute($values);
.......
Related
I need some help
Is there a way to make this in PDO? https://stackoverflow.com/a/1899508/6208408
Yes I know I could change to mysql but I use a mssql server and can't use mysql. I tried some things but I'm not as good with PDO as mysql... It's hard to find some good examples of inserting array's into database with PDO. So quickly said I have a PDO based code connected to a mssql webserver.
best regards joep
I tried this before:
//id
$com_id = $_POST['com_id'];
//array
$mon_barcode = $_POST['mon_barcode'];
$mon_merk = $_POST['mon_merk'];
$mon_type = $_POST['mon_type'];
$mon_inch = $_POST['mon_inch'];
$mon_a_date = $_POST['mon_a_date'];
$mon_a_prijs = $_POST['mon_a_prijs'];
$data = array_merge($mon_barcode, $mon_merk, $mon_type, $mon_inch, $mon_a_date, $mon_a_prijs);
try{
$sql = "INSERT INTO IA_Monitor (Com_ID, Barcode, Merk, Type, Inch, Aanschaf_dat, Aanschaf_waarde) VALUES (?,?,?,?,?,?,?)";
$insertData = array();
foreach($_POST['mon_barcode'] as $i => $barcode)
{
$insertData[] = $barcode;
}
if (!empty($insertData))
{
implode(', ', $insertData);
$stmt = $conn->prepare($sql);
$stmt->execute($insertData);
}
}catch(PDOException $e){
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
The code below should fix your problems.
$db_username='';
$db_password='';
$conn = new \PDO("sqlsrv:Server=localhost,1521;Database=testdb", $db_username, $db_password,[]);
//above added per #YourCommonSense's request to provide a complete example to a code fragment
if (isset($_POST['com_id'])) { //was com_id posted?
//id
$com_id = $_POST['com_id'];
//array
$mon_barcode = $_POST['mon_barcode'];
$mon_merk = $_POST['mon_merk'];
$mon_type = $_POST['mon_type'];
$mon_inch = $_POST['mon_inch'];
$mon_a_date = $_POST['mon_a_date'];
$mon_a_prijs = $_POST['mon_a_prijs'];
$sql = "INSERT INTO IA_Monitor (Com_ID, Barcode, Merk, Type, Inch, Aanschaf_dat, Aanschaf_waarde) VALUES (?,?,?,?,?,?,?)";
try {
$stmt = $conn->prepare($sql);
foreach ($mon_barcode as $i => $barcode) {
$stmt->execute([$com_id, $barcode, $mon_merk[$i], $mon_type[$i], $mon_inch[$i], $mon_a_date[$i], $mon_a_prijs[$i]]);
}
} catch (\PDOException $e) {
echo $sql . "<br>" . $e->getMessage();
}
}
$conn = null;
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'm building an website using php and html, im used to receiving data from a database, aka Dynamic Website, i've build an CMS for my own use.
Im trying to "simplify" the receiving process using php and functions.
My Functions.php looks like this:
function get_db($row){
$dsn = "mysql:host=".$GLOBALS["db_host"].";dbname=".$GLOBALS["db_name"];
$dsn = $GLOBALS["dsn"];
try {
$pdo = new PDO($dsn, $GLOBALS["db_user"], $GLOBALS["db_pasw"]);
$stmt = $pdo->prepare("SELECT * FROM lp_sessions");
$stmt->execute();
$row = $stmt->fetchAll();
foreach ($row as $row) {
echo $row['session_id'] . ", ";
}
}
catch(PDOException $e) {
die("Could not connect to the database\n");
}
}
Where i will get the rows content like this: $row['row'];
I'm trying to call it like this:
the snippet below is from the index.php
echo get_db($row['session_id']); // Line 22
just to show whats in all the rows.
When i run that code snippet i get the error:
Notice: Undefined variable: row in C:\wamp\www\Wordpress ish\index.php
on line 22
I'm also using PDO just so you would know :)
Any help is much appreciated!
Regards
Stian
EDIT: Updated functions.php
function get_db(){
$dsn = "mysql:host=".$GLOBALS["db_host"].";dbname=".$GLOBALS["db_name"];
$dsn = $GLOBALS["dsn"];
try {
$pdo = new PDO($dsn, $GLOBALS["db_user"], $GLOBALS["db_pasw"]);
$stmt = $pdo->prepare("SELECT * FROM lp_sessions");
$stmt->execute();
$rows = $stmt->fetchAll();
foreach ($rows as $row) {
echo $row['session_id'] . ", ";
}
}
catch(PDOException $e) {
die("Could not connect to the database\n");
}
}
Instead of echoing the values from the DB, the function should return them as a string.
function get_db(){
$dsn = "mysql:host=".$GLOBALS["db_host"].";dbname=".$GLOBALS["db_name"];
$dsn = $GLOBALS["dsn"];
$result = '';
try {
$pdo = new PDO($dsn, $GLOBALS["db_user"], $GLOBALS["db_pasw"]);
$stmt = $pdo->prepare("SELECT * FROM lp_sessions");
$stmt->execute();
$rows = $stmt->fetchAll();
foreach ($rows as $row) {
$result .= $row['session_id'] . ", ";
}
}
catch(PDOException $e) {
die("Could not connect to the database\n");
}
return $result;
}
Then call it as:
echo get_db();
Another option would be for the function to return the session IDs as an array:
function get_db(){
$dsn = "mysql:host=".$GLOBALS["db_host"].";dbname=".$GLOBALS["db_name"];
$dsn = $GLOBALS["dsn"];
$result = array();
try {
$pdo = new PDO($dsn, $GLOBALS["db_user"], $GLOBALS["db_pasw"]);
$stmt = $pdo->prepare("SELECT * FROM lp_sessions");
$stmt->execute();
$rows = $stmt->fetchAll();
foreach ($rows as $row) {
$result[] = $row['session_id'];
}
}
catch(PDOException $e) {
die("Could not connect to the database\n");
}
return $result;
}
Then you would use it as:
$sessions = get_db(); // $sessions is an array
and the caller can then make use of the values in the array, perhaps using them as the key in some other calls instead of just printing them.
As antoox said, but a complete changeset; change row to rows in two places:
$rows = $stmt->fetchAll();
foreach ($rows as $row) {
echo $row['session_id'] . ", ";
}
Putting this at the start of the script after <?php line will output interesting warnings:
error_reporting(E_ALL|E_NOTICE);
To output only one row, suppose the database table has a field named id and you want to fetch row with id=1234:
$stmt = $pdo->prepare("SELECT * FROM lp_sessions WHERE id=?");
$stmt->bindValue(1, "1234", PDO::PARAM_STR);
I chose PDO::PARAM_STR because it will work with both strings and integers.
I stupidly built my web application with mysqli. Now, I'm trying to convert my data abstraction layer to pdo, but for some reason the insert query is giving me trouble. my shortcut insert function is called from the controller, and I was hoping to keep it in the name format with the table name and column/values array as the parameters.
I commented where I think the problem is below. Please help.
function insert($table, array $columns_values) {
// connect to db
$dbh = $this->db_connect();
$i = 0;
$columns = array();
$values = array();
$params = array();
foreach($columns_values as $column => $value) {
$i++;
$param = array($i => $value);
array_push($params, $param);
array_push($columns, $column);
array_push($values, '?');
}
// turn arrays into comma separated list
$columns = implode(",", $columns);
$values = implode(",", $values);
$stmt = $dbh->prepare("INSERT INTO $table ($columns) VALUES ($values)");
foreach ($params as $param_stmt) {
// i think this is where the problem is
foreach ($param_stmt as $placeholder => $value) {
$stmt->bindParam($placeholder, $value);
}
}
$stmt->execute();
return $stmt;
} // end insert()
I wouldn't do it your way. After a few minutes, I came up with this:
/**
* Function to insert a list of values to the database.
*
* #param PDO $pdo
* #param string $table
* #param array $columns_values
*
* #throws \Exception
* #throws \PDOException
*/
function insert_to_db(PDO $pdo, $table, array $columns_values) {
//Some data validation.
if (empty($columns_values)) {
throw new \Exception("Insert at least one value.");
}
if (empty($table)) {
throw new \Exception("Table may not be empty.");
}
//Implode all of column names. Will become the columns part of the query.
$str_columns = implode(", ", array_keys($columns_values));
//Implode all column names after adding a : at the beginning.
//They will become the placeholders on the values part.
$prepared_column_names = array_map(function ($el) {
return ":$el";
}, array_keys($columns_values));
$prepared_str_columns = implode(", ", $prepared_column_names);
//The query itself. Will look like "INSERT INTO `$table` (col1, col2, col3) VALUES (:col1, :col2, :col3);"
$query = "INSERT INTO `$table` ($str_columns) VALUES ($prepared_str_columns);";
//Prepare the query
$stmt = $pdo->prepare($query);
//Iterate over the columns and values, and bind the value to the placeholder
foreach ($columns_values as $column => $value) {
$stmt->bindValue(":$column", $value);
}
//Execute the query
$stmt->execute();
}
Things I changed
I don't instantiate the PDO object inside of the function. The function needs one in order to work, so it should be one of the arguments!
I throw Exceptions in case of an error. It's a better way of handling errors.
I use named placeholders instead of unnamed ones (:name vs ?). Produces more readable, easier to follow queries, should you ever need to debug.
Added comments to code. Again, you understand what you wrote now, but will you 6 months from now?
I made use of array_keys() to automatically generate an array full of keys (i.e. the columns), instead of looping and manually adding one.
Some tips
When you instantiate a PDO object, make sure it throws PDOExceptions on error! Like so:
new PDO($dsn, $user, $pass, array(PDO::PARAM_ERRMODE => PDO::ERRMODE_EXCEPTION));
or
$pdo = new PDO($dsn, $user, $pass);
$pdo->setAttribute(PDO::PARAM_ERRMODE, PDO::ERRMODE_EXCEPTION);
That way, you don't need to explicitly check for errors each time, you use a single try catch block for the whole thing, and you're good:
try {
insert_to_db($pdo, $table, $array_of_columns_and_values);
}
catch (\Exception $e) { //Will catch all kinds of exceptions, including PDOExceptions
echo $e->getMessage();
}
You haven't checked that your prepare() actually succeeded:
$sql = "INSERT ....";
$stmt = $dbh->prepare($sql);
if (!$stmt) {
die($sql . $dbh->errorInfo());
}
Never assume a query succeeded, especially when you're building one totally dynamically as you are.
Without seeing what your original $columns_values array looks like.
Hope it helps
<?php
function insert($table, $values){
$dbh = $this->db_connect();
$fieldnames = array_keys($values[0]);
$sql = "INSERT INTO $table";
/*** set the field names ***/
$fields = '( ' . implode(' ,', $fieldnames) . ' )';
/*** set the placeholders ***/
$bound = '(:' . implode(', :', $fieldnames) . ' )';
/*** put the query together ***/
$sql .= $fields.' VALUES '.$bound;
//INSERT INTO testtable( id ,col1 ,col2 ) VALUES (:id, :col1, :col2 )
/*** prepare and execute ***/
$query = $dbh->prepare($sql);
foreach($values as $vals){
$query->execute($vals);
/* Array
(
[id] =
[col1] = someval1
[col2] = Someval21
)*/
}
}
//Multi Insert
$insert = array(array('id'=>'','col1'=>'someval1','col2'=>'Someval21'),
array('id'=>'','col1'=>'someval2','col2'=>'Someval22'),
array('id'=>'','col1'=>'someval3','col2'=>'Someval23'),
array('id'=>'','col1'=>'someval4','col2'=>'Someval24')
);
insert('testtable',$insert);
?>