Am I saving myself from sql injections? - php

Am I doing this right? Will this help avoid sql injections?
$deleteid = htmlspecialchars(strip_tags(mysql_real_escape_string($_POST['listid'])));
mysql_send("DELETE FROM stage where listid='$deleteid'");

No.
You should call nothing but mysql_real_escape_string.
The htmlspecialchars and strip_tags functions are used to encode strings to be displayed as HTML.
They should not be used with SQL

It may prevent SQL injection attacks, but its a poor way to approach it. Use prepared queries instead.
Since your comment says you're systematically making changes to your whole site, go with the better approach. While you're at it, you may want to move to a non-MySQL-specific database API, in case you want to switch to another backend later.

Apart from the mentioned suggestions (only mysql_real_escape_string but even better prepared statements), I would like to add that it is always useful to analyse exactly the value you are trying to clean / make safe.
If your ID is supposed to be an integer, I would simply use intval($_POST['listid']) to make sure the result is an integer and reserve mysql_real_escape_string for strings (although I personally would use prepared statements / PDO).

Yes, using mysql_real_escape_string on values that are intended to be used in string declarations in MySQL statements will prevent you from SQL injections. That’s the exact purpose of that function.
But you don’t need the other two functions strip_tags and htmlspecialchars. Because these functions are used to either remove (HTML) tags and replace the HTML special characters by character references respectively. They are not intended to protect you against SQL injections.
In fact, using strip_tags and/or htmlspecialchars after mysql_real_escape_string could break the escaping under some certain instances (e.g. when using non-US-ASCII based character sets, see also addslashes() Versus mysql_real_escape_string()). So make sure that you use that function right before inserting its returned value into the SQL statement.
Apart from encoding the output using mysql_real_escape_string you could also validate the input using ctype_digit:
if (ctype_digit($_POST['listid'])) {
mysql_send("DELETE FROM stage where listid='".$_POST['listid']."'");
} else {
// invalid value
}
This validation ensures that only (positive) integer values are used in the query that don’t need to be escaped.

I always use a database helper class on all my projects.. that way I don't have to use mysql_real_escape_string keeping code clean and easy to read you'll be safe from injections if you forget to use it.
Below is an example the one I use...
<?php
final class DatabaseException extends Exception {
function __construct($strErrMessage, $intErrCode) {
parent::__construct($strErrMessage, $intErrCode);
}
}
class Database {
protected $host = ""; //database server
protected $user = ""; //database login name
protected $pass = ""; //database login password
protected $database = ""; //database name
protected $prefix = ""; //table prefix
protected $connected = false;
protected $db = null;
protected $record = array();
protected $error = "";
protected $errno = 0;
//table name affected by SQL query
protected $field_table= "";
//number of rows affected by SQL query
protected $affected_rows = 0;
protected $link_id = 0;
protected $query_id = array();
function __construct($server, $user, $pass, $database, $pre='') {
$this->connected = false;
$this->host = $server;
$this->user = $user;
$this->pass = $pass;
$this->database = $database;
$this->prefix = $pre;
$this->connect();
}
function __destruct() {
//mysql_close($this->link_id);
}
public function connect() {
if ($this->link_id > 0 && $this->connected && mysql_ping($this->link_id)) { return; }
$this->link_id = mysql_pconnect($this->host, $this->user, $this->pass);
if (!$this->link_id) { //open failed
throw new DatabaseException("mysql_pconnect failed",0);
}
if(!#mysql_select_db($this->database, $this->link_id)) {//no database
throw new DatabaseException("mysql_select_db failed",0);
}
$this->server='';
$this->user='';
$this->pass='';
$this->database='';
$this->connected = true;
$this->query("SET time_zone = '".Settings::get('db.timezone_offset')."';",TRUE);
}
public function escape($string) {
if(get_magic_quotes_gpc())
$string = stripslashes($string);
return mysql_real_escape_string($string);
}
public function insert($table,$data,$tbl_key='id') {
$v='';
$n='';
foreach($data as $key=>$val) {
$n.="`$key`, ";
if(strtolower($val)=='null')
$v.="NULL, ";
elseif(strtolower($val)=='now()')
$v.="NOW(), ";
elseif(strcmp(substr($val,0,7),'**ESC**') == 0)
$v .= str_replace('**ESC**','',$val);
else
$v.= "'".$this->escape($val)."', ";
}
if ($v=='' || $n=='')
return false;
$q = "INSERT INTO `".$this->prefix.$table."` ";
$q .= "(". rtrim($n, ', ') .") VALUES (". rtrim($v, ', ') .");";
if($this->query($q)){
$id=mysql_insert_id();
if ($id === 0) { // The ID generated for an AUTO_INCREMENT column by the previous INSERT query on success,
// 0 if the previous query does not generate an AUTO_INCREMENT value, or FALSE if no MySQL
// connection was established.
return TRUE;
}
return $id;
}
else {
return false;
}
}
public function replace($table,$data,$tbl_key='id') {
$v='';
$n='';
foreach($data as $key=>$val) {
$n.="`$key`, ";
if(strtolower($val)=='null')
$v.="NULL, ";
elseif(strtolower($val)=='now()')
$v.="NOW(), ";
elseif(strcmp(substr($val,0,7),'**ESC**') == 0)
$v .= str_replace('**ESC**','',$val);
else
$v.= "'".$this->escape($val)."', ";
}
if ($v=='' || $n=='')
return false;
$q = "REPLACE INTO `".$this->prefix.$table."` ";
$q .= "(". rtrim($n, ', ') .") VALUES (". rtrim($v, ', ') .");";
if($this->query($q)){
$id=mysql_insert_id();
if ($id === 0) { // The ID generated for an AUTO_INCREMENT column by the previous INSERT query on success,
// 0 if the previous query does not generate an AUTO_INCREMENT value, or FALSE if no MySQL
// connection was established.
return TRUE;
}
return $id;
}
else {
return false;
}
}
public function update($table,$data,$where='1') {
$q = "UPDATE `".$this->prefix.$table."` SET ";
foreach($data as $key=>$val) {
if(strtolower($val)=='null') $q .= "`$key` = NULL, ";
elseif(strtolower($val)=='now()') $q .= "`$key` = NOW(), ";
elseif(strcmp(substr($val,0,7),'**ESC**') == 0) $q .= "`$key` = ".str_replace('**ESC**','',$val);
else $q.= "`$key`='".$this->escape($val)."', ";
}
$q = rtrim($q, ', ') . ' WHERE '.$where.';';
$result = $this->query($q);
if ($result) {
}
return $result;
}
public function search($table, $field, $value, $exact=FALSE)
{
$value = escape($value);
if (!$exact) {
$q = "select * from $table where $field like '%$value%';";
} else {
$q = "select * from $table where $field = '$value';";
}
return $this->query($q);
}
public function delete($table,$where='1') {
$q = "DELETE FROM `".$this->prefix.$table."` ";
$q .= " WHERE ".$where.";";
$result = $this->query($q);
if ($result) {
}
}
public function query($sql,$reset=FALSE) {
//echo "<pre>$sql</pre>";
$this->connect();
$command = strtok(trim($sql)," \n\t");
switch (strtoupper(trim($command))) {
case "SELECT":
case "SHOW":
case "DESCRIBE":
case "EXPLAIN":
if (isset($this->query_id[md5($sql)]) && $reset==FALSE) {
$row = mysql_fetch_array($this->query_id[md5($sql)], MYSQL_ASSOC);
if ($row == FALSE) {
unset($this->query_id[md5($sql)]);
return FALSE;
} else {
return $row;
}
} else {
$this->query_id[md5($sql)] = #mysql_query($sql, $this->link_id);
if (!$this->query_id[md5($sql)]) {
throw new DatabaseException(mysql_error($this->link_id),mysql_errno($this->link_id));
}
}
$row = mysql_fetch_array($this->query_id[md5($sql)], MYSQL_ASSOC);
if ($row == FALSE) {
unset($this->query_id[md5($sql)]);
return FALSE;
} else {
return $row;
}
break;
default:
return #mysql_query($sql, $this->link_id);
break;
}
}
}
?>
To create and use the Database Class:
$db = new Database("db.host","db.user","db.pass","db.database");
Getting data from $_POST into your db is super simple if all your form elements are named the same as your table fields.. for example:
$data = $_POST;
$ok = $db->update('mytable', $data, 'something = something_else'); //$ok will be false if something went wrong

in this case
mysql_query("DELETE FROM stage WHERE listid=".intval($_POST['listid']));
full reference: dynamical SQL syntax explained

use stored procedures and grant execute permissions only to your app db user (plus the myriad of other benefits sprocs bring)

Related

PHP Commands out of sync; you can't run this command now

I've seen this question before but all the solutions do not work for me. The main solution is to store the result which I already do. Most people say I am running 2 simultaneous queries which I don't understand. I may have used this function below more than once but I always free and close the statement so not sure why this is happening.
You can most likely ignore the top half of the function which just generates a string to represent the types. This is the full DB class I made:
(I edited it since I originally posted it and replaced self::$connection with self::$db)
class DB {
private static $dbhost = "localhost";
private static $dbuser = "some_user"; // placeholder
private static $dbpass = "some_assword"; // placeholder
private static $dbname = "database_name"; // placeholder
private static $db;
public static function connect() {
self::$db = new mysqli(self::$dbhost, self::$dbuser, self::$dbpass, self::$dbname);
if (self::$db->connect_errno) {
die("Database mysqli failed: " .
self::$db->connect_error . " (" .
self::$db->connect_errno . ")"
);
}
}
// IGNORE THIS! It just formats the parameters for the
// call_user_func_array function to work correctly.
private static function getBindings(&$params) {
$types = "";
$bindings = array();
foreach ($params as $value) {
switch (gettype($value)) {
case "integer":
$types .= "i";
break;
case "double":
$types .= "d";
break;
case "string":
$types .= "s";
break;
default:
$types .= "s";
break;
}
}
foreach($params as $key => $value)
$bindings[$key] = &$params[$key]; // assign to references (because bind_param requires references)
// to add a string of variable types to the start of the $bindings array (such as 'sss')
array_unshift($bindings, $types);
return $bindings;
}
public static function query($query, $params) {
if (!isset(self::$db)) { self::connect(); }
if (empty($params)) {
// prepared statement not needed
return self::$db->query($query);
}
$successful = false;
$bindings = self::getBindings($params);
// MySQL prepared statement execution:
$statement = self::$db->prepare($query);
call_user_func_array(array($statement, 'bind_param'), $bindings);
$statement->execute();
$statement->store_result();
if ($statement->num_rows > 0) {
// for select queries
$successful = $statement->get_result(); // does not work! (returns boolean)
echo self::$db->errno; // 2014
echo "<br />";
echo self::$db->error; // Commands out of sync; you can't run this command now
echo "<br />";
// this method works fine (but I need to return the result set!):
/*$name = false; $link = false;
$statement->bind_result($name, $link);
while ($statement->fetch()) {
echo 'name: '.$name.'<br>';
echo 'link: '.$link.'<br>';
}*/
} else if ($statement->affected_rows > 0) {
// for insert queries
$successful = true;
}
$statement->free_result();
$statement->close();
return $successful;
}
public static function close() {
if (isset(self::$db)) self::$db->close();
}
}
EDIT: This is what one of my requests looks like (I have queried 2 requests on this same page using my DB class and DB::query(...) function):
$result = DB::query("SELECT * FROM table_name;");
if ($result) {
while ($row = $result->fetch_assoc()) {
// do stuff
}
$result->close();
}
For the love of what is sane, change your driver to PDO and make all this code into
public static function query($query, $params = NULL)
{
if (!$params) {
return self::$connection->query($query);
}
$statement = self::$connection->prepare($query);
$statement->execute($params);
return $statement;
}
to be used like this
$result = DB::query("SELECT * FROM table_name");
foreach($result as $row) {
// do stuff
}
The MySQL documentation regarding Commands out of sync suggest two possibilities:
You have used a result and are trying to execute a new query before freeing the last result.
You are running two queries (not necessarily simultaneously) without using or storing the result between each one.
The logic in your code shows the only situation where you are not freeing results is when no prepared statement is required. The answer to your problem may be to deal with this particular result and free or store it.
I can see from your code self::$connection is a static reference, therefore it could be possible that any query executed in that scope is using the same connection. It is hard to tell without being able to see your full class.

What is the right way to add a variable where-clause to this update function

I'm made a database class in php. Now i was testing the update function in it. It returns an syntax error or an unknown column error depending on how the where-clause is formed.
I tried:
'woord = \'uiteindelijk\'' and 'woord = \"uiteindelijk\"' and
'woord = "uiteindelijk"' and more
I also tried different quotes and backsticks in de functions query but it al gave me the same errors.
My question is what is the right way to form the where-clause is this example if it possible ofcourse. And if not how can i fix it.
part of database.mysqli.php
<?php
class myDB {
private $mysqli;
public function __construct() {
require_once('config.php');
$this->mysqli = new mysqli(HOST, USERNAME, PASSWORD, DB_NAME);
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
}
public function close() {
$this->mysqli->close();
}
private function check($input) {
if(is_string($input)) {
$input = trim($input);
return $this->mysqli->real_escape_string($input);
}
elseif(is_int($input)) {
return $input;
}
elseif($input === true || $input === false) {
return $input;
}
else {
die('invalid input');
}
}
public function update($table, $data, $where) {
$table = $this->check($table);
$where = $this->check($where);
$result = '';
if (is_array($data)) {
$update = array();
foreach ($data as $key => $val) {
$key = $this->check($key);
$val = $this->check($val);
$update[] .= $key . '=\'' . $val . '\'';
}
$query = 'UPDATE ' . $table . ' SET ' . implode(',', $update) . ' WHERE ' . $where;
if($this->mysqli->query($query)) {
$result = 'Last updated row id is: '.$this->mysqli->insert_id;
}
else {
$result = $this->mysqli->error;
}
}
return $result;
}
test.php
<!DOCTYPE HTML>
<html>
<head>
</head>
<body>
<?php
require_once('database.mysqli.php');
$db = new myDB;
$data = array('woord' => 'gewoontjes', 'lengte' => 10);
$result = $db->update('galgje', $data, 'woord = \'uiteindelijk\'');
echo $result;
$db->close();
?>
</body>
</html>
The problem comes from escape_string in your check method. This function is used to escape precise parts inside a statement, you cannot apply it to the where clause as a whole in such a generic way.
If you ever know for sure that your inputs are safe (not containing special characters breaking the sql statement, malicious or not), then simply remove the escaping.
Or if you think that they may contain special characters, for good reasons or to possibly drag a sql injection, then you have to provide a more constrained interface so that you can build the where clause yourself with the appropriate escaping. For example :
public function update($table, $data, $woord) {
...
$where = 'woord = \'' . $this->check($woord) . '\'';
...
}
Edit: I know it may sound too much constrained but security comes at a price. For something more flexible, you could have a look at prepared statements. They let you use placeholders, for example WHERE woord = ? AND id < ?, which you can bind to variables with something like :
$stmt->bind_param('si', $woord, $id); // 'si' -> 1:string, 2:integer
In this case, mysqli applies escaping internaly on bound strings, so you don't have to worry about it.
Note that you cannot use a placeholder to replace the whole where clause. WHERE ? with $stmt->bind_param('s', $where); will not work.
Last thing, PDO, an alternative API to access your database in PHP, supports named placeholders (WHERE woord = :woord instead of WHERE woord = ?).

Issues using PHP MySQL Built-In Functions inside a class

I am working with a MySQL Database and having some issues while trying to get data from several built-in PHP MySQL methods. I have written a class to interact with the database, and here are the relevant bits:
<?php
include("includes/Config.inc.php");
include_once("ChromePHP.class.php");
class Database{
private $db;
private $hostname;
private $username;
private $password;
private $schema;
function __construct() {
if(func_num_args() == 0){
$this->hostname = conf_hostname;
$this->username = conf_username;
$this->password = conf_password;
$this->schema = conf_schema;
}
else{
$params = func_get_args();
$this->hostname = $params[0];
$this->username = $params[1];
$this->password = $params[2];
$this->schema = $params[3];
}
$this->open();
}
private function open(){
$this->db = mysql_connect($this->hostname, $this->username, $this->password) or die ('Error connecting to mysql');
mysql_select_db($this->schema, $this->db);
mysql_query("SET NAMES utf8");
}
public function executeQuery($query){
$results = mysql_query($query, $this->db) or die ("Error in query: $query. ".mysql_error());
return $results;
}
public function executeNonQuery($query){
mysql_query($query, $this->db) or die ("Error in query: $query. ".mysql_error());
$info = mysql_info($this->db);
if($info){
$bits = explode(' ', $info);
return $bits[4];
}
return false;
}
public function close(){
mysql_close($this->db);
}
public function escape($string){
$output = mysql_real_escape_string($string , $this->db);
return $output;
}
public function getRegionTree(){
$query = "SELECT COUNT(parent.Name) - 2 as level, node.Name AS Name, node.ID, node.Parent
FROM Region AS node, Region AS parent
WHERE node.LeftVal BETWEEN parent.LeftVal AND parent.RightVal and node.Name <> 'Earth'
GROUP BY node.ID
ORDER BY node.LeftVal";
$result = $this->executeQuery($query);
$last_level = 0;
$output = '<ul id="regionTree">'.PHP_EOL;
while ($row = mysql_fetch_assoc($result)) {
$link = '<li>'.PHP_EOL.''.$row["Name"]."".PHP_EOL;
$diff = $last_level - $row["level"];
if($diff == 0){
// Sibling
$output .= ($row["level"] != 0) ? '</li>'.PHP_EOL.$link:$link;
}
elseif($diff < 0){
// Child
$demoter = '<ul>'.PHP_EOL;
for ($i=0; $i > $diff; $i--) {
$output .= $demoter;
}
$output .= $link;
}
else{
// Parent
$promoter = '</li>'.PHP_EOL.'</ul>';
for ($i=0; $i < $diff; $i++) {
$output .= ($row["level"] != 0) ? $promoter.PHP_EOL."</li>":$promoter;
}
$output .= $link;
}
$last_level = $row["level"];
}
$output .= "</li></ul>";
return $output;
}
public function addRegion($name, $type, $parentID){
$query = "select Name, Region_Type from Region where ID = ".$parentID;
$result = $this->executeQuery($query);
if($result){
$row = mysql_fetch_assoc($result);
$query = "call AddRegion('".$name."', '".$type."', '".$row["Name"]."', '".$row["Region_Type"]."', #returnCode, #returnMessage)";
$result = $this->executeQuery($query);
if($result){
return true;
}
else{
$query = "select #returnCode as code, #returnMessage as message";
$result = $this->executeQuery($query);
while($row = mysql_fetch_assoc($result)){
print_r($row);
}
return false;
}
}
return false;
}
public function getInfo(){
return mysql_info();
}
public function editRegion($id, $name, $type){
$query = "update Region set Name = '$name', Region_Type = '$type' where ID = $id";
if($this->executeNonQuery($query) > 0){
return true;
}
return false;
}
}
$db = new Database();
?>
With this Database class I am able to successfully make queries, get region trees, and successfully change data in the database using the ExecuteNonQuery function. However, any attempts I have made to use mysql_info, mysql_affected_rows, or other similar functions fails, making it really difficult to write any error handling code. To make matters stranger yet, if I run the following code:
<?php
$db = mysql_connect("localhost", "User", "Password") or die ('Error connecting to mysql');
mysql_select_db("DB", $db);
mysql_query("update Region set Name = 'test' where ID = 594", $db);
echo mysql_info($db);
?>
I am able to get results as expected. Any Ideas?
Are you using mysql_info and mysql_error outside the Database class? And if so how are you referencing the database connection? If you don't identify the database connection then:
The MySQL connection. If the link identifier is not specified, the last
link opened by mysql_connect() is assumed. If no such link is found,
it will try to create one as if mysql_connect() was called with no
arguments. If no connection is found or established, an E_WARNING
level error is generated.
So internally you should be doing mysql_info($this->db); to get mysql_info. Accessing $db externally requires you to write something to get around it being private.
But if you are going to be doing database stuff in an object-oriented mode you really should investigate PDO.
After adding "or die()" statements in several places in my script, I was surprised to see that nothing was actually failing to work, instead it was failing to work the way I expected it to. The problem I was having as it turns out, was that splitting the output of mysql_info (on the space character) resulted in several indices in the array containing nothing, as would be generated by inconsistent whitespace in the output of mysql_info. The index that I thought (based upon counting spaces visually) would contain an integer instead contained a string, and I was attempting to compare that string against the number 0, which won't work. I have updated my executeNonQuery function as follows:
public function executeNonQuery($query){
mysql_query($query, $this->db) or die ("Error in query: $query. ".mysql_error());
$info = mysql_info($this->db);
if($info){
$output = array();
$bits = explode(' ', $info);
$output["rowsMatched"] = $bits[2];
$output["rowsChanged"] = $bits[5];
$output["warnings"] = $bits[8];
return $output;
}
return false;
}

Fetch data from MySQL using OOP

I'm a beginner in OOP PHP.
I'm trying to make a class that will connect,query and fetch data
I done the below coding
class MySQL {
private $set_host;
private $set_username;
private $set_password;
private $set_database;
public function __Construct($set_host, $set_username, $set_password){
$this->host = $set_host;
$this->username = $set_username;
$this->password = $set_password;
$con= mysql_connect($this->host, $this->username, $this->password);
if(!$con){ die("Couldn't connect"); }
}
public function Database($set_database)
{
$this->database=$set_database;
mysql_select_db($this->database)or die("cannot select Dataabase");
}
public function Fetch($set_table_name){
$this->table_name=$set_table_name;
$query=mysql_query("SELECT * FROM ".$this->table_name);
$result= mysql_fetch_array($query);
}
}
$connect = new MySQL('localhost','root','');
$connect->Database('cms');
$connect->Fetch('posts');
what I'm trying to achieve is this
$connect = new MySQL('localhost','root','');
$connect->Database('cms');
$connect->Fetch('posts');
and I want to fetch the data using a format like this
echo $result[0];
but I'm not getting that logic to make this happen
please help
Thanks!
Your Fetch function is only pulling one row from the database, and you aren't returning the results...
The method isn't the best, but in order to achieve what you're trying to do:
public function Fetch($set_table_name){
$query=mysql_query("SELECT * FROM ".$set_table_name);
$result = array();
while ($record = mysql_fetch_array($query)) {
$result[] = $record;
}
return $result;
}
This will make each row a part of $result, but you'll have to access it like this:
You would call the fetch function like this:
$result = $connect->Fetch('posts');
echo $result[0]['columnName']; // for row 0;
Or in a loop:
for ($x = 0; $x < count($result); $x++) {
echo $result[$x][0] . "<BR>"; // outputs the first column from every row
}
That said, fetching the entire result set into memory is not a great idea (some would say it's a very bad idea.)
Edit: It also looks like you have other issues with your class... I have to run but will check back tomorrow and if others haven't set you straight I will expand.
Edit2: Ok, going to do a once-over on your class and try to explain a few things:
class MySQL {
//declaring the private variables that you will access through $this->variable;
private $host;
private $username;
private $password;
private $database;
private $conn; // Adding the connection, more on this later.
public function __Construct($set_host, $set_username, $set_password){
$this->host = $set_host;
$this->username = $set_username;
$this->password = $set_password;
// Combining the connection & connection check using 'or'
// Notice that I removed the semi-colon after the mysql_connect function
$this->conn = mysql_connect($this->host, $this->username, $this->password)
or die("Couldn't connect");
}
public function Database($set_database)
{
$this->database=$set_database;
// Adding the connection to the function allows you to have multiple
// different connections at the same time. Without it, it would use
// the most recent connection.
mysql_select_db($this->database, $this->conn) or die("cannot select Dataabase");
}
public function Fetch($table_name){
// Adding the connection to the function and return the result object instead
return mysql_query("SELECT * FROM ".$table_name, $this->conn);
}
}
$connect = new MySQL('localhost','root','');
$connect->Database('cms');
$posts = $connect->Fetch('posts');
if ($posts && mysql_num_rows($posts) > 0) {
echo "Here is some post data:<BR>";
while ($record = mysql_fetch_array($posts)) {
echo $record[0]; // or a quoted string column name instead of numerical index.
}
} else {
echo "No posts!";
}
I hope this helps... It should get you started at least. If you have more questions you should ask them separately.
That's because $result is set inside the Fetch function. It won't be available outside the Fetch function.
Instead of this line $result= mysql_fetch_array($query);, you'll want something like return mysql_fetch_array($query);.
And then in your code
$row = $connect->Fetch('posts');
// do something with $row
On another note, your Fetch function only applies to database queries that return one row. You'll have to separate the mysql_query & mysql_fetch_array calls into another function if you want to loop through rows in a query result.
And on another note, you shouldn't need to encapsulate this code into a class. PHP already provides OOP-based database classes called PDO, or PHP Data Objects. There's a learning curve to it, but it's best practice, and will help secure your code against things like SQL injection.
This is a pretty good tutorial: http://www.giantflyingsaucer.com/blog/?p=2478
I would make a function that returns the value of the object.
public function returnData($data){
return $this->$data;
}
Then within the page you wish to get the data on just initiate the class and call the function within that class.
$post->returnDate("row name here");
<?php
//database.php
class Databases{
public $con;
public function __construct()
{
$this->con = mysqli_connect("localhost", "root", "", "giit");
if(!$this->con)
{
echo 'Database Connection Error ' . mysqli_connect_error($this->con);
}
}
public function insert($table_name, $data)
{
$string = "INSERT INTO ".$table_name." (";
$string .= implode(",", array_keys($data)) . ') VALUES (';
$string .= "'" . implode("','", array_values($data)) . "')";
if(mysqli_query($this->con, $string))
{
return true;
}
else
{
echo mysqli_error($this->con);
}
}
public function selectmulti($selecttype,$table_name)
{
$array = array();
$query = "SELECT ".$selecttype." FROM ".$table_name."";
$result = mysqli_query($this->con, $query);
while($row = mysqli_fetch_assoc($result))
{
$array[] = $row;
}
return $array;
}
public function selectsingle($selecttype,$table_name)
{
$query = "SELECT ".$selecttype." FROM ".$table_name."";
$result = mysqli_query($this->con, $query);
$row = mysqli_fetch_assoc($result);
return $row;
}
}
?>
<?php
$data = new Databases;
$post_data = $data->selectmulti('*','centerdetail');
$n = 1;
foreach($post_data as $post)
{
echo $n.'.'.$post['CenterCode'].'___';
$n += 1;
}
echo '<br>';
$post_data = $data->selectsingle('*','centerdetail');
echo $post_data['CenterCode'];
?>

What is the correct and easiest way to do prepared statements with PHP's mysqli?

I have been using the old mysql api in PHP for a long time and want to start using mysqli for both speed and security with a new project I'm working on. I've looked through the manual and read several tutorials, but I'm finding a lot of conflicting and somewhat confusing information on how to do prepared statements in mysql.
Is there anything in this code that doesn't need to be there, and is there anything that is missing? Also, is this the easiest way to do something simple like this (seems somewhat involved for such a simple task)?
Procedural:
// build prepared statement
$query = mysqli_prepare($link, "SELECT email FROM users WHERE id = ?");
// bind parameters to statement
mysqli_stmt_bind_param($query, 's', $_GET['id']);
// execute statement
mysqli_stmt_execute($query);
// bind the variables to the result
mysqli_stmt_bind_result($query, $email);
// print the results
while (mysqli_stmt_fetch($query)) {
echo $email;
}
// close the statement
mysqli_stmt_close($query);
// close connection
mysqli_close($link);
Object-Oriented:
// build prepared statement
$query = $link->prepare("SELECT email FROM users WHERE id = ?");
// bind parameters to statement
$query->bind_param('s', $_GET['id']);
// execute statement
$query->execute();
// bind the variables to the result
$query->bind_result($email);
// print the results
while ($query->fetch()) {
echo $email;
}
// close the statement
$query->close();
// close connection
$link->close();
Here's the guts of a semi-self-explanatory class that encapsulates mysqli, including prepared statements, which are quite tricky. It's pretty well tested - I've been using it for a year now without change.
It only implements prepared statements to Execute SQL commands because they change data and often require nasty encoding tricks otherwise. If you want SELECTs, it's left as an exercise for the reader - it's easier. :)
<?php
class Db
{
var $_mysqli;
var $_result;
var $_error_msg;
public function __construct($server, $user, $password, $name)
{
$this->_mysqli = new mysqli("p:".$server, $user,
$password, $name);
if($this->_mysqli->connect_errno)
{
$this->_error_msg = $this->_mysqli->connect_error;
}
}
public function __destruct()
{
}
private function sql_select($sql)
{
$this->_mysqli->query("SET NAMES 'utf8'"); // a little help for UTF8 io
$this->_result = $this->_mysqli->query($sql);
}
private function sql_close()
{
$this->_mysqli->close();
}
public function ErrorMessage()
{
return $this->_error_msg;
}
public function SqlRows($sql)
{
$rows = array();
$result = $this->sql_select($sql);
if($this->IsError())
{
return $rows;
}
while($row = $result->fetch_array())
{
$rows[] = $row;
}
$result->free();
return $rows;
}
public function SqlObjects($sql)
{
$objects = array();
$result = $this->sql_select($sql);
while($object = $this->_result->fetch_object())
{
$objects[] = $object;
}
$result->free();
return $objects;
}
public function SqlOneObject($sql)
{
$result = $this->sql_select($sql);
$obj = $result->fetch_object();
$result->free();
return $obj;
}
public function SqlOneRow($sql)
{
$result = $this->sql_select($sql);
if(! is_object($result))
return null;
if($result->num_rows > 0)
$row = $result->fetch_array();
else
$row = null;
$result->free();
return $row;
}
public function SqlOneValue($sql)
{
$result = $this->sql_select($sql);
if(!empty($result))
{
$row = $result->fetch_array();
}
$result->free();
return empty($row) ? null : $row[0] ;
}
// returns number of affected rows
public function SqlExecute($sql)
{
$this->_result = $this->_mysqli->query($sql);
return $this->affected_rows();
}
private function affected_rows()
{
return $this->_mysqli->affected_rows;
}
private function IsError()
{
if(empty($this->_mysqli))
return false;
return !empty($this->_mysqli->error);
}
// arguments are sql and an array of
// argument references (not values).
public function SqlExecutePS($sql, $args)
{
$stmt = $this->_mysqli->prepare($sql);
// make the type-string
$typestr = make_typestring($args);
$params = array($typestr);
$params = array_merge($params, $args);
call_user_func_array(array($stmt, 'bind_param'), $params);
$stmt->execute();
$ret = $this->affected_rows();
$stmt->close();
return $ret;
}
public function SqlExists($sql)
{
$result = $this->SqlOneRow($sql);
return !empty($result[0]);
}
function make_typestring($args)
{
assert(is_array($args));
$ret = "";
foreach($args as $arg)
{
switch(gettype($arg))
{
case "boolean":
case "integer":
$ret .= "i";
break;
case "double":
$ret .= "d";
break;
case "string":
$ret .= "s";
break;
case "array":
case "object":
case "resource":
case "NULL":
default:
// call it a blob and hope
// you know what you're doing.
$ret .= "b";
break;
}
}
return $ret;
}
}
?>

Categories