I have 3 files:
DB.class.php - which handles all the databases.
Site.class.php - contains a function to return the latest entries in a database.
index.php - trying to print the array passed.
I am trying to pass an array into index.php from Site.class.php which is using a function from DB.class.php to put the mysql results into an associative array.
index.php:
<?php
// index.php
include 'classes/Site.class.php';
$site = new Site();
print_r($site->latestBookmarks());
?>
Site.class.php:
<?php
// Site.class.php
require_once 'DB.class.php';
class Site {
function latestBookmarks() {
$result = mysql_query("SELECT url, title FROM site ORDER BY id DESC");
$db = new DB();
return $db->processRowSet($result);
}
}
?>
DB.class.php:
<?php
// DB.class.php
class DB {
protected $db_name = "project";
protected $db_user = "root";
protected $db_pass = "root";
protected $db_host = "localhost";
// Open up a connection to the database.
public function connect() {
$connection = mysql_connect($this->db_host, $this->db_user, $this->db_pass);
mysql_select_db($this->db_name);
return true;
}
// Takes a MySQL row and returns an associative array where the keys in the array are the column names in the row set.
public function processRowSet($rowSet, $singleRow=false) {
$resultArray = array();
while ($row = mysql_fetch_assoc($rowSet)) {
array_push($resultArray, $row);
}
if ($singleRow === true)
return $resultArray[0];
return $resultArray;
}
// Select rows from the database.
public function select($table, $where) {
$sql = "SELECT * FROM $table WHERE $where";
$result = mysql_query($sql);
if (mysql_num_rows($result) == 1)
return $this->processRowSet($result, true);
return $this->processRowSet($result);
}
// Update a current row in the database.
public function update($data, $table, $where) {
foreach ($data as $column => $value) {
$sql = "UPDATE $table SET $column = $value WHERE $where";
mysql_query($sql) or die(mysql_error());
}
return true;
}
// Insert a new row into the database.
public function insert($data, $table) {
$columns = "";
$values = "";
foreach ($data as $column => $value) {
$columns .= ($columns == "") ? "" : ", ";
$columns .= $column;
$values .= ($values == "") ? "" : ", ";
$values .= $value;
}
$sql = "INSERT INTO $table ($columns) VALUES ($values)";
mysql_query($sql) or die(mysql_error());
return mysql_insert_id();
}
}
?>
A few problems I noticed:
You run a query in function latestBookmarks before you connect to the db;
In your function connect you connect to a database, but the result is discarded immediately, $connection is lost as soon as the function finishes.
You have no connection to the database when you run this line:
$result = mysql_query("SELECT url, title FROM site ORDER BY id DESC");
You will need to adjust your code to send the query string to the DB instance for processing. You can add a method to DB to execute mysql_query, and pass the query in like from Site:: latestBookmarks() like this:
$db = new DB();
$db->executeQuery("SELECT url, title FROM site ORDER BY id DESC");
return $db->processRowSet();
Related
I am trying to learn object oriented programming.
The problem what I have is how to add link under mysqli_query() inside the class.
In procedural style I just create a $variable with connection details and then using it inside the mysqli_query($variable, $sql) etc.
In my class I have function connect() which will connect to database and return true but Haw can I use it inside my mysqli_query() please? please see the code here:
<?php
class DB {
protected $db_name = 'OOP_forum';
protected $db_user = 'Marcel';
protected $db_pass = *****;
protected $db_host = 'localhost';
public function connect() {
$connection = mysqli_connect($this->db_host, $this->db_user, $this->db_pass);
mysqli_select_db($connection, $this->db_name);
return true;
}
public function processRowSet($rowSet, $singleRow = false) {
$resultArray = array();
while($row = mysqli_fetch_assoc($rowSet)) {
arraypush($resultArray, $row);
}
if($singleRow==true) {
return $resultArray[0];
}else {
return $resultArray; }
}
public function select ($table, $where, $column = '*') {
$sql = "SELECT $column FROM $table WHERE $where";
$result = mysqli_query($sql);
if(mysqli_num_row($result) == 1 ){
return $this->processRowSet($result, true);
} else
{ return $this->processsRowSet($result);
}
}
public function update ($data, $table, $where) {
foreach ($data as $column->$value) {
$sql = "UPDATE $table SET $column = $value WHERE $where";
mysqli_query($sql) or die(mysqli_error());
}
return true;
}
public function delete ($table, $column, $where) {
$sql = "DELETE FROM $table WHERE $column = $where";
if (query($sql)=== TRUE) {
echo "Record Deleted sucessfully";
}else {
echo "Error deleting record: " . $connection->error;
}
}
public function insert($data, $table) {
$columns = "";
$values = "";
foreach ($data as $column->$value) {
$columns .= ($columns == "") ? "": ", " ;
$columns .= $column;
$values .= ($values == "") ? "" : ", ";
$values .= $value;
}
$sql = "insert into $table ($columns) values ($values)";
mysqli_query($sql) or die(mysqli_error());
return mysqli_insert_id();
}
}
?>
Before trying to learn OOP programming you have to learn basic OOP syntax.
In order to do so forget for a while about creating your own classes and learn how to use already made ones. So, first of all learn how to use mysqli. Which is already a class.
Better yet, learn PDO instead, as, unlike mysqli, it's already a ready to use database access class, with it you don't need functions like processRowSet, for example.
I'm using singleton design pattern for connect to database.In below I run a query on my database and I want to fetch data from this query :
$db = Db::connect();
$query = $db->query("SELECT * FROM myTable");
while ($row = ???) {
// echo 'myTable' fields here. like = echo $row['someField']
}
my Db class:
class Db
{
private $connection;
private static $instance;
private function __construct()
{
$host = "localhost";
$user = "root";
$pass = "";
$name = "dictionary";
$this->connection = new mysqli($host, $user, $pass, $name);
}
public static function connect()
{
if (self::$instance == null) {
self::$instance = new Db();
}
return self::$instance;
}
public function query($sql)
{
$result = $this->connection->query($sql);
$records = array();
while ($row = $result->fetch_assoc()) {
$records[] = $row;
}
return $records;
}
}
What should I write instead of ??? in my code ?
Replace
while ($row = ???) {
// echo 'myTable' fields here. like = echo $row['someField']
}
with
foreach($query as $row)
echo $row['someField'];
Note : You may want to rename $query to $rows, for example, since this is a more appropriate name.
In each iteration of while loop, use array_shift() function to get the current row from the result set, like this:
while ($row = array_shift($query)) {
echo $row['someField'] . "<br />";
}
Here's the reference:
array_shift()
Your call to your Database class's ->query() method returns an array of result rows. So all you need to do is process that array like any other
$db = Db::connect();
$rows = $db->query("SELECT * FROM myTable");
foreach ($rows as $row ) {
echo $row['someField'];
}
I have a HTML form which has more than 25 entries.
I know how to insert normal form data into MySQL database using PHP PDO. But I just want to know if there is any alternative way in which I can store the form entries to an array and insert the data into database using the array.
Because writing an insert statement for more than 25 columns is cumbersome.
You could always use a PDO wrapper class, I use the class below to handle most of my PDO queries:
class DB {
protected
// Return from mysql statement
$data = array(),
// Used for checking whether something was added to the JSON object and remove it if the table column doens't exist
$table_cols = array(),
// Storing the table name we are working with
$table = '';
protected static
// PDO connection to the DB
$_conn = null,
// The DB credentials retrieved from the ini file
$_credentials = array ();
private
$_id = -1,
$_keys = array(),
$_values = array(),
$_last_insert_id = -1,
$_results = array();
//
// PUBLIC FUNCTIONS
//
public function __construct () {
if (self::$_conn === null) {
self::setCredentials();
try {
self::$_conn = new \PDO("mysql:host=" . self::$_credentials['host'] . ";dbname=" . self::$_credentials['dbname'] , self::$_credentials['username'], self::$_credentials['password']);
} catch (\PDOException $e) {
DebugLog::instance('DB')->error($e, 'db_connection');
}
}
}
public function insert ($data) {
$data = $this->checkCols($data);
// Allows us to quickly clone data by removing the id and inserting as a new record
if (isset($data['id'])) {
unset($data['id']);
}
$this->data = $data;
$this->setDataBinding();
$sql = "INSERT INTO `" . self::$_credentials['dbname'] . "`.`{$this->table}` (`" . implode('`, `', $this->_keys) . "`) VALUES (:" . implode(', :', $this->_keys) . ");";
return $this->prepareAndExecute($sql);
}
public function update ($data) {
$data = $this->checkCols($data);
if (!isset($data['id'])) {
// Houston we have a problem, there needs to be an id to update a record
DebugLog::instance('DB')->error("No ID set for Update: " . implode(', ', array_keys($data)), 'db_id_' . $this->table);
} else {
// We need to unset the id because it shouldn't be in the data binding
// But we still hold onto it for the where clause
$id = $data['id'];
unset($data['id']);
$this->data = $data;
$this->setDataBinding();
$sql = "UPDATE `" . self::$_credentials['dbname'] . "`.`{$this->table}` SET ";
$query_string = "";
foreach ($this->_keys as $i => $key) {
$query_string .= "`{$key}` = :{$key}, ";
}
$query_string = trim($query_string);
if (substr($query_string, -1) === ',') {
$query_string = substr($query_string, 0, -1);
}
$sql .= $query_string . " WHERE `id` = '{$id}'";
return $this->prepareAndExecute($sql);
}
return false;
}
public function remove ($id) {
$this->rawQuery("DELETE FROM `{$this->table}` WHERE `id` = '{$id}';");
}
public function rawQuery ($sql) {
try {
$pdo = self::$_conn->query($sql);
$pdo->setFetchMode(\PDO::FETCH_ASSOC);
} catch (\PDOException $e) {
DebugLog::instance('DB')->error($e, 'db_query_' . $this->table);
return array();
}
return $pdo->fetchAll();
}
//
// GETTERS
//
public function getColumns () {
return $this->table_cols;
}
public function getLastInsertID () {
return $this->_last_insert_id;
}
public function getRecord ($id) {
$this->_id = $id;
$response = $this->rawQuery("SELECT * FROM `{$this->table}` WHERE `id` = '{$id}'");
$this->_results = $response[0];
}
public function getResults () {
return $this->_results;
}
public function close () {
$this->setDefaults();
}
//
// PROTECTED FUNCTIONS
//
protected function initColumns () {
$sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '" . self::$_credentials['dbname'] . "' AND TABLE_NAME = '{$this->table}';";
$response = $this->rawQuery($sql);
if (!empty($response)) {
return $this->parseColumns($response);
}
return array();
}
//
// PRIVATE FUNCTIONS
//
private function setDataBinding () {
$this->_keys = array_keys($this->data);
foreach ($this->data as $k => $v) {
$this->_values[':' . $k] = $v;
}
}
private function prepareAndExecute ($sql) {
try {
$q = self::$_conn->prepare($sql);
$q->setFetchMode(\PDO::FETCH_ASSOC);
if ($q->execute($this->_values)) {
while ($r = $q->fetch()) {
$this->_results[] = $r;
}
$this->_last_insert_id = self::$_conn->lastInsertId();
return true;
} else {
DebugLog::instance('DB')->error('Failed to execute', 'db_' . $this->table);
}
} catch (\PDOException $e) {
DebugLog::instance('DB')->error($e, 'db_' . $this->table);
}
return false;
}
private function checkCols ($array) {
foreach ($array as $col => $val) {
if (!in_array($col, $this->table_cols)) {
unset($array[$col]);
}
}
return $array;
}
private static function setCredentials () {
// I actually use a config file here, instead of hard coding
self::$_credentials = array(
'host' => '',
'dbname' => '',
'username' => '',
'password' => ''
);
}
private function parseColumns ($cols) {
$array = array();
foreach ($cols as $index => $col_array) {
$array[] = $col_array['COLUMN_NAME'];
}
return $array;
}
private function setDefaults () {
$this->data = array();
$this->table_cols = array();
$this->table = '';
self::$_conn = null;
$this->_keys = array();
$this->_values = array();
$this->_last_insert_id = -1;
$this->_results = array();
}
}
Then for each table, create a class that extends the class above. For example, lets say we have a users table:
class UsersTable extends DB {
public function __construct () {
// Parent constructor creates the DB connection
parent::__construct();
// Now let's set the desired table based on this class
$this->table = "users";
// Set the table columns, for mysql column validation
$this->table_cols = $this->initColumns();
}
}
Usage is than as simple as:
$table = new UsersTable();
$table->insert($record);
As long as your array has the 25 values in the same order as the table you can use unnamed parameters and lazy binding See PDO info
$sql ="INSERT INTO table_name VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,)";
$stmt = $dbh->prepare($sql);
$stmt->execute($array);
I've been working on learning OOP and classes, and I wanted a critique on a simple project I'm writing.
I wrote a couple of classes to make it easier for me to generate a table using MySQL and PDO. It's still being worked on, but I wanted to make sure that I haven't "Broken" anything.
My main question is I'm wondering if what I wrote is still considered "secure", mostly from SQL injection.
index.php:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Database Class</title>
</head>
<body>
<?php
include 'class.MySQL.php';
include 'class.TableBuilder.php';
//Check to make sure a valid connection has been made
//If so, instantiate the object and login to the database
$db = (new MySQLDatabase_Object)->check_login();
//Define the columns headings
//Can be empty, but shouldn't be
//Example:
//"First Name"
//"Last Name"
$columns = array(
'First Name',
'Last Name',
'Street Address'
);
//Build the 'SELECT' query fields
//Cannot be empty
//Example:
//"leads.fname" => "fname means"
//"leads.fname" => "fname"
$fields = array(
'leads.fname' => 'fname',
'leads.lname' => 'lname',
'leads.addr_street' => 'addr_street'
);
//Builds the 'FROM' query values
//This will be a single table name
//Cannot be empty
//Example:
//"leads"
$tables = array('leads');
//Builds the 'WHERE' query
//Can only use the JOIN query or the WHERE query, not both
//Can be empty
//Examples:
//"WHERE leads.fname LIKE '%Walt%'"
//"WHERE leads.fname = 'Walter'"
$where = array(
);
//Builds the JOIN query
//Can only use the JOIN query or the WHERE query, not both
//Can be empty
//Examples:
//"INNER JOIN appointments" => "leads.id = appointments.lead"
//"INNER JOIN leads_notes" => "leads.id = leads_notes.id_lead"
$join = array(
);
//Builds the AND/OR/NOT query
//Can be empty
//Examples:
//"AND leads.assigned = 1"
//"OR leads.assigned != 0"
//"NOT leads.assigned = 0"
$and = array(
);
//Sets the 'ORDER BY' clause
//Can be empty
//Example:
//"leads.lname ASC"
//"leads.fname DESC"
$order = array(
);
//Build and return the query
$query = MySQLDatabase_Object::query_builder_select($fields, $tables, $where, $join, $and, $order);
//Gather the result set from the query and
//place them in a nested array
$result_set = MySQLDatabase_Object::results($fields, $db, $query);
//Build the table, based on the result set and columns
//and print the table to the screen
$table = new MySQLTable;
echo $table->buildTable($columns, $result_set);
?>
</body>
</html>
class.MySQL.php:
<?php
class MySQLDatabase_Object {
//Create the database connection and attempt to login to the database
private function login() {
$host = "localhost"; //Host Name
$port = '3306'; //Default MySQL Port
$dbname = "xxxxxx"; //Database Name
$db_username = "xxxxxx"; //MySQL Username
$db_password = "xxxxxx"; //MySQL Password
$dsn = "mysql:host=$host;port=$port;dbname=$dbname"; //Data Source Name = Mysql
$db = new PDO($dsn, $db_username, $db_password); //Connect to DB
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $db;
}
//Public-facing login method to log into the database and return the $db PDO
public function check_login() {
$db = $this->login();
return $db;
}
static function query_builder_select($fields, $tables, $where, $join, $and, $order) {
//Process the SELECT fields
$select_fields = self::check_fields($fields);
//Process the FROM field
$tables = self::check_table($tables);
//Processes the JOIN or WHERE fields
if (!empty($where) && !empty($join)) {
die("You can only use one of the JOIN or WHERE clauses. Not both.");
} elseif (!empty($where)) {
$where = self::check_where($where);
} elseif (!empty($join)) {
$where = self::check_join($join);
} else {
$where = null;
}
//Process the AND/OR/NOT fields
$and = self::check_and($and);
//Process the ORDER BY fields
$order = self::check_order($order);
//Build the SELECT query
$query = "SELECT $select_fields ";
$query .= "FROM $tables";
if (!is_null($where)) {
$query .= " $where";
}
if (!is_null($and)) {
$query .= " $and";
}
if (!is_null($order)) {
$query .= " ORDER BY $order";
}
echo $query;
return $query;
}
private static function check_fields($fields) {
//Purpose: Gathers all the values from the $fields array
//and formats them correctly to generate a correct "SELECT" statement
//Check for an empty array
if (empty($fields)) {
die("No query fields selected");
}
//
$select_fields = '';
foreach ($fields AS $key => $value) {
$select_fields .= "$key AS $value,";
}
//Remove the trailing comma from the last element in the array
$select_fields = trim($select_fields, ',');
return $select_fields;
}
private static function check_table($tables) {
//Get the table array elements and seperate them with a comma
if (!empty($tables)) {
$tables = implode(',', $tables);
$tables = trim($tables, ',');
} else {
die('No Tables selected');
}
return $tables;
}
private static function check_where($where) {
//Get the WHERE array elements and seperate them with a comma
if (!empty($where)) {
$where = implode(',', $where);
$where = trim($where, ',');
} else {
$where = null;
}
return $where;
}
private static function check_join($join) {
$join_options = '';
if (!empty($join)) {
foreach ($join AS $key => $value) {
$join_options .= " $key ON $value ";
}
} else {
$join_options = null;
}
return $join_options;
}
private static function check_and($and) {
//Get the WHERE array elements and seperate them with a comma
if (!empty($and)) {
$and = implode(' ', $and);
$and = trim($and, ' ');
} else {
$and = null;
}
return $and;
}
private static function check_order($order) {
//Get the order array elements and seperate them with a comma
if (!empty($order)) {
$order = implode(',', $order);
$order = trim($order, ',');
} else {
$order = null;
}
return $order;
}
static function results($fields, $db, $query) {
//Run the prepared query
$stmt = $db->prepare($query);
$stmt->execute();
$results = array();
$field_array = array();
foreach ($stmt->fetchAll(PDO::FETCH_OBJ) as $row) {
//Build the nested arrays
foreach ($fields AS $key => $value) {
$$value = $row->$value;
array_push($field_array, $$value);
}
//Add the nested arrays to the main array ($results)
array_push($results, $field_array);
$field_array = array();
}
return $results;
}
}
class.TableBuilder.php:
<?php
class MySQLTable {
public function buildTable($columns, $result_set) {
//Create an empty table
$table = '';
$table .= '<table border="1">';
//Build the column structure, passed in from the $columns array
$table .= "<tr>";
foreach ($columns as $column) {
$table .= "<td>$column</td>";
}
$table .= "</tr>";
//Build the rows from the $result_set array
foreach ($result_set AS $array) {
$table .= "<tr>";
//Pass each nested array to the table as a single row
//per nested array
foreach ($array AS $table_cell) {
$table .= "<td>$table_cell</td>";
}
//Placeholder for adding additional columns (usually button columns)
// $table .= "<td><button type='button'>Test</button></td>";
$table .= "</tr>";
}
//Complete the table
$table .= "</table>";
return $table;
}
}
In order to get this to work, you need to modify class.MySQL.php with your database information.
You can modify $fields and $columns in index.php to see how it works. In theory, you should be able to name your columns in the '$columns' array, your MySQL SELECT fields in the $fields array, and your table name in $tables.
If you need more info, I'd be glad to help.
I'm aware that there is only simple 'WHERE' and 'JOIN' clause handling. I will be working on this next.
Thanks for any critique!
I am using same query again and again on different pages in between to fetch result. I want to make a function for this query.
$result = mysql_query(" SELECT name FROM tablename where id= '$row[name_id]'");
$row = mysql_fetch_array($result);
echo $row ['name'];
How to make and how to call the function?
sample class stored sample.php
class sample
{
function getName(id)
{
$result = mysql_query("SELECT name FROM tablename where id='$id'");
$row = mysql_fetch_array($result);
return $row ['name'];
}
}
use page include sample.php,then create object,then call getName() function.
<?php
include "db.class.php";
include "sample.php";
$ob=new sample(); //create object for smaple class
$id=12;
$name=$ob->getName($id); //call function..
?>
This is a good idea but first of all you have to create a function to run queries (as you have to run various queries way more often than a particular one)
function dbget() {
/*
easy to use yet SAFE way of handling mysql queries.
usage: dbget($mode, $query, $param1, $param2,...);
$mode - "dimension" of result:
0 - resource
1 - scalar
2 - row
3 - array of rows
every variable in the query have to be substituted with a placeholder
while the avtual variable have to be listed in the function params
in the same order as placeholders have in the query.
use %d placeholder for the integer values and %s for anything else
*/
$args = func_get_args();
if (count($args) < 2) {
trigger_error("dbget: too few arguments");
return false;
}
$mode = array_shift($args);
$query = array_shift($args);
$query = str_replace("%s","'%s'",$query);
foreach ($args as $key => $val) {
$args[$key] = mysql_real_escape_string($val);
}
$query = vsprintf($query, $args);
if (!$query) return false;
$res = mysql_query($query);
if (!$res) {
trigger_error("dbget: ".mysql_error()." in ".$query);
return false;
}
if ($mode === 0) return $res;
if ($mode === 1) {
if ($row = mysql_fetch_row($res)) return $row[0];
else return NULL;
}
$a = array();
if ($mode === 2) {
if ($row = mysql_fetch_assoc($res)) return $row;
}
if ($mode === 3) {
while($row = mysql_fetch_assoc($res)) $a[]=$row;
}
return $a;
}
then you may create this particular function you are asking for
function get_name_by_id($id){
return dbget("SELECT name FROM tablename where id=%d",$id);
}
You should probably parse the database connection as well
$database_connection = mysql_connect('localhost', 'mysql_user', 'mysql_password');
function get_row_by_id($id, $database_link){
$result = mysql_query("SELECT name FROM tablename where id= '{$id}");
return mysql_fetch_array($result);
}
Usage
$row = get_row_by_id(5, $database_connection);
[EDIT]
Also it would probably help to wrap the function in a class.
function getName($id){
$result = mysql_query("SELECT name FROM tablename where id= '$row[name_id]'");
$row = mysql_fetch_array($result);
return $row ['name'];
}
call the function by
$id = 1; //id number
$name = getName($id);
echo $name; //display name