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.
Related
I'm in the middle of creating a custom Database Class to suit the requirements of the company i'm developing for. I currently have this:
class DBC {
protected $Link;
protected $Results;
public function __construct($Host = null,$User = null ,$Pass = null,$Database = null){
if ($Host === null OR $User === null OR $Pass === null OR $Database === null){
trigger_error("Incorrect Parameters Passed In The Database Link", E_USER_WARNING);
}
if (is_string($Host) AND is_string($User) AND is_string($Pass) AND is_string($Database)){
$this->Link = new mysqli($Host,$User,$Pass,$Database);
}else{
trigger_error("Expecting String(s), Array passed in one or more connection parameters",E_USER_ERROR);
}
}
public function Query ($Query,$Params){
$Query = $this->Link->prepare($Query);
$Query->bind_param();
}
}
Now.. I'm having a problem with how to sucessfully bind the parameters to the prepared statement.. For example, A Query will be submitted with this:
$DB = new DBC("Host","User","pass","database");
$DB->Query("SELECT * FROM Test WHERE Col=?",array("SearchCriteria"));
I've hit a block with figuring out how to bind_param and bind_result based on the results. A more clear insight is the normal procedure of MySQLi:
$SearchCriteria = "String";
$Query = $Database->prepare("SELECT * FROM Test WHERE Col=?");
$Query->bind_param('s',$SearchCriteria);
$Query->execute();
$Query->bind_results(/* Variables to match the column set */);
$Query->fetch();
$Query->close();
How can I bind the results and params to the prepared statement?
Below are copies of functions I use in a class that extends the mysqli class which do what you are asking.
function bind_placeholder_vars(&$stmt,$params,$debug=0) {
// Credit to: Dave Morgan
// Code ripped from: http://www.devmorgan.com/blog/2009/03/27/dydl-part-3-dynamic-binding-with-mysqli-php/
if ($params != null) {
$types = ''; //initial sting with types
foreach ($params as $param) { //for each element, determine type and add
if (is_int($param)) {
$types .= 'i'; //integer
} elseif (is_float($param)) {
$types .= 'd'; //double
} elseif (is_string($param)) {
$types .= 's'; //string
} else {
$types .= 'b'; //blob and unknown
}
}
$bind_names = array();
$bind_names[] = $types; //first param needed is the type string
// eg: 'issss'
for ($i=0; $i<count($params);$i++) { //go through incoming params and added em to array
$bind_name = 'bind' . $i; //give them an arbitrary name
$$bind_name = $params[$i]; //add the parameter to the variable variable
$bind_names[] = &$$bind_name; //now associate the variable as an element in an array
}
if ($debug) {
echo "\$bind_names:<br />\n";
var_dump($bind_names);
echo "<br />\n";
}
//error_log("better_mysqli has params ".print_r($bind_names, 1));
//call the function bind_param with dynamic params
call_user_func_array(array($stmt,'bind_param'),$bind_names);
return true;
}else{
return false;
}
}
function bind_result_array($stmt, &$row) {
// Credit to: Dave Morgan
// Code ripped from: http://www.devmorgan.com/blog/2009/03/27/dydl-part-3-dynamic-binding-with-mysqli-php/
$meta = $stmt->result_metadata();
while ($field = $meta->fetch_field()) {
$params[] = &$row[$field->name];
}
call_user_func_array(array($stmt, 'bind_result'), $params);
return true;
}
However, it sounds like you are doing something similar to what I have already done and have been using in many projects for a while now. Copy the contents of this pastebin (better_mysqli.php) into a new file and name it 'better_mysqli.php'
Then use it in your php program like so:
// include the class
include_once('better_mysqli.php');
// instantiate the object and open the database connection
$mysqli = new better_mysqli('yourserver.com', 'username', 'password', 'db_name');
if (mysqli_connect_errno()) {
die("Can't connect to MySQL Server. Errorcode: %s\n", mysqli_connect_error()), 'error');
}
// do a select query
$sth = $mysqli->select('select somecol, othercol from sometable where col1=? and col2=?', $row, array('col1_placeholder_value', 'col2_placeholder_value'));
while ($sth->fetch()) {
echo "somecol: ". $row['somecol'] ."<br />\n";
echo "othercol: ". $row['othercol'] ."<br />\n";
}
// the nice thing about this class is that the statement is only prepared once so if you use it again the already prepared statement is automatically used:
// do another select query with different placeholder values
$sth = $mysqli->select('select somecol, othercol from sometable where col1=? and col2=?', $row, array('other_col1_placeholder_value', 'other_col2_placeholder_value'));
while ($sth->fetch()) {
echo "somecol: ". $row['somecol'] ."<br />\n";
echo "othercol: ". $row['othercol'] ."<br />\n";
}
// the class supports the following methods: select, update, insert, and delete
// example delete:
$mysqli->delete('delete from sometable where col1=?', array('placeholder_val1'));
I've got a database query function that works well -- except that I'm running into what's apparently a known issue with mysqli prepared statements and longtext fields. What happens is that the longtext field always comes up empty even though running the query through phpMyAdmin works fine. According to http://www.workinginboxershorts.com/php-mysqli-returns-empty-variables-from-longtext-column, switching the datatype to text solves the problem. However, in my case I'd really prefer to leave the field as longtext as I can foresee times when that extra space would be valuable.
I'm using parameterized queries, which evidently is the problem. Here's my function:
// Bind results to an array
// $stmt = sql query, $out = array to be returned
function stmt_bind_assoc (&$stmt, &$out) {
$data = mysqli_stmt_result_metadata($stmt);
$fields = array();
$out = array();
$fields[0] = $stmt;
$count = 1;
while($field = mysqli_fetch_field($data)) {
$fields[$count] = &$out[$field->name];
$count++;
}
call_user_func_array('mysqli_stmt_bind_result', $fields);
}
// DB Query
// $query = SQL query, $params = array of parameters, $rs = whether or not a resultset is expected, $newid = whether or not to retrieve the new ID value;
// $onedimensionkey = key required to convert array into simple one dimensional array
function db_query($query, $params, $rs = true, $newid = false, $onedimensionkey = false) {
$link = mysqli_connect(DB_SERVER, DB_USER, DB_PASS, DB_NAME);
if (!$link) {
print 'Error connecting to MySQL Server. Errorcode: ' . mysqli_connect_error();
exit;
}
// Prepare the query and split the parameters array into bound values
if ($sql_stmt = mysqli_prepare($link, $query)) {
if ($params) {
$types = '';
$new_params = array();
$params_ref = array();
// Split the params array into types string and parameters sub-array
foreach ($params as $param) {
$types .= $param['type'];
$new_params[] = $param['value'];
}
// Cycle the new parameters array to make it an array by reference
foreach ($new_params as $key => $parameter) {
$params_ref[] = &$new_params[$key];
}
call_user_func_array('mysqli_stmt_bind_param', array_merge(array($sql_stmt, $types), $params_ref));
}
}
else {
print 'Error: ' . mysqli_error($link);
exit();
}
// Execute the query
mysqli_stmt_execute($sql_stmt);
// If there are results to retrive, do so
if ($rs) {
$results = array();
$rows = array();
$row = array();
stmt_bind_assoc($sql_stmt, $results);
while (mysqli_stmt_fetch($sql_stmt)) {
foreach ($results as $key => $value) {
$row[$key] = $value;
}
$rows[] = $row;
}
if ($onedimensionkey) {
$i = 0;
foreach ($rows as $row) {
$simplearray[$i] = $row[$onedimensionkey];
$i++;
}
return $simplearray;
}
else {
return $rows;
}
}
// If there are no results but we need the new ID, return it
elseif ($newid) {
return mysqli_insert_id($link);
}
// Close objects
mysqli_stmt_close($sql_stmt);
mysqli_close($link);
}
According to the link that I posted there is a workaround involving the order in which things are done, but either I'm handling my query in a completely different manner than the example or I'm simply not understanding something important.
Thanks to anyone who can help!
EDIT: Thanks to Corina's answer, I've solved this -- for anyone else who runs into the problem, you will simply need to add the following after the mysql_stmt_execute command:
// Execute the query
mysqli_stmt_execute($sql_stmt);
// Store results
mysqli_stmt_store_result($sql_stmt);
I managed to solve the same issue by calling mysqli_stmt_store_result before binding the data.
Someone had the same problem and shared the answer on the php.net website:
Apparently, if you have longtext present, you HAVE to call
store_result before using bind_result.
http://bugs.php.net/bug.php?id=47928
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'];
?>
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;
}
}
?>
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)