php mysql delete statment does not run - php

My SQL Statement works in phpMyAdmin, but when I use PHP to run it from my webpage, it does nothing.
My code is as below, which always returns true. I have solved this problem, but the primary problem is that the code does not delete the row.
// Delete Area
public function deleteArea($product_area_id){
$this->db->query("
DELETE
FROM product_area
WHERE product_area_id = :product_area_id
LIMIT 1
");
//bind
$this->db->bind(':product_area_id', $product_area_id);
//Execute
if($this->db->execute()){
return true;
} else {
return false;
}
}
My database class:
public function bind($param, $value, $type = null) {
if (is_null ( $type )) {
switch (true) {
case is_int ( $value ) :
$type = PDO::PARAM_INT;
break;
case is_bool ( $value ) :
$type = PDO::PARAM_BOOL;
break;
case is_null ( $value ) :
$type = PDO::PARAM_NULL;
break;
default :
$type = PDO::PARAM_STR;
}
}
$this->stmt->bindValue ( $param, $value, $type );
}
public function query($query) {
$this->stmt = $this->dbh->prepare($query);
}
public function execute(){
return $this->stmt->execute();
}

You're mixing PDO with the mysql_ functions. They do NOT work interoperably. What you need here is rowCount
$this->db->query("
DELETE
FROM product_area
WHERE product_area_id = :product_area_id
LIMIT 1
");
//bind
$this->db->bind(':product_area_id', $product_area_id);
//Execute
$this->db->execute();
if(this->db->rowCount() > 0){

A comment quote from the op (the last comment at the moment):
The primary problem is, it will not delete. even though the sql
statment is correct when tested directly in phpmyadmin. the secondary
problem is, it will also say true. even though it didn't delete.
Machavity solved the secondary problem. the primary remains. -
codenoob
TLDR: // Note: PDOStatement::execute .... Returns TRUE on success or FALSE on failure.
So that is why it returns 1 all the time for you. See the below for 2 files to test this with a change using rowCount() off of a PDOStatement object.
You said in comments that the primary problem remains. I have no problem using the below after sort of hand crafting a database class, because you did not offer one (you mention one). Note the use of try/catch blocks.
Frankly we don't know if you had any exceptions or how you are handling them, or whether or not you have error reporting activated. The below should survive any testing, assuming the pdo object can successfully return the rowCount() value.
Schema for testing:
create table product_area
( product_area_id int primary key,
theName varchar(100) not null
);
-- blockA begin
truncate product_area;
insert product_area (product_area_id,theName) values
(1,'Houston zone B'),(2,'Houston zone BH'),(20,'Houston zone Z');
-- blockA end
Test File:
For the test file, there are only a few lines of code near the top for testing in the section called "Mini test area"
<?php
// pdo_del_test_20160703.php
// related to answering http://stackoverflow.com/questions/38061597 at the moment
error_reporting(E_ALL);
ini_set("display_errors", 1);
include "myPDO_DB.php"; // Database class. The class name = myPDO_DB
// Mini test area BEGIN:
$a1=new aClass();
$ret=$a1->deleteArea(2);
echo "retValue=".$ret."<br>";
// Mini test area ... END
class aClass {
private $db=null;
public function __construct(){
echo "in constructor1<br>";
$this->db=new myPDO_DB();
echo "in constructor2<br>";
//$this->db=null;
echo "in constructor3<br>";
}
public function deleteArea($product_area_id){
$this->db->query("
DELETE
FROM product_area
WHERE product_area_id = :product_area_id
LIMIT 1
");
// Note: PDOStatement::execute .... Returns TRUE on success or FALSE on failure.
//
// so on a Delete call, it just says sure, OK, done with that (if no exception)
// It doesn't give feedback natively as to whether or not a row was actually deleted
//
//bind
$this->db->bind(':product_area_id', $product_area_id);
//Execute
// Don't forget to run schema `blockA` before testing (so that data is there)
if ($this->db->execute()) { // if this function returns anything other than TRUE you have exception problems
$pdo_rowcount=$this->db->stmt->rowCount(); // see http://php.net/manual/en/pdostatement.rowcount.php
// Depending on your systems ability to get pdo.rowCount() to work, consider the following
// Please see http://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_row-count
$this->db->query("select row_count()"); // from mysql "Information Functions". Based on prior mysql call.
$mysql_rowcount=$this->db->execute();
// but note, row_count() in mysql is not exactly a solution for the majority of systems out there.
// http://www.heidisql.com/forum.php?t=9791
// on mysql 5.5 and my 5.6.24, it returns 0
// so depending on your system, you will choose between $pdo_rowcount and $mysql_rowcount
return $pdo_rowcount; // your best bet, bust test it on your setup.
}
else {
// do something
return 0; // you would have already endured an exception though
}
}
}
?>
Database class:
<?php
// myPDO_DB.php
//
error_reporting(E_ALL);
ini_set("display_errors", 1);
include "db_connect_info.php"; // brings in the "defines" .. Shoot for a secure o/s vault in this file.
class myPDO_DB {
// will grab the stub from http://culttt.com/2012/10/01/roll-your-own-pdo-php-class/
//
// and then build your class into it (because you did not provide it)
//
// and then further improve it with try/catch blocks that were lacking
//
private $host = DB_HOST; // these were brought in with the include above. File not shown.
private $user = DB_USER;
private $pass = DB_PASS;
private $dbname = DB_NAME;
private $dbh;
public $stmt; // was made public to get into rowCount(); .... change this for your needs
private $error;
public function __construct(){
// Set DSN
$dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname;
// Set options
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false
);
// Create a new PDO instanace
try{
$this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
echo "Connect Ok<br>";
}
catch(PDOException $e){
$this->error = $e->getMessage();
}
}
public function bind($param, $value, $type = null) {
try {
if (is_null ( $type )) {
switch (true) {
case is_int ( $value ) :
$type = PDO::PARAM_INT;
break;
case is_bool ( $value ) :
$type = PDO::PARAM_BOOL;
break;
case is_null ( $value ) :
$type = PDO::PARAM_NULL;
break;
default :
$type = PDO::PARAM_STR;
}
}
$this->stmt->bindValue ( $param, $value, $type );
}
catch(PDOException $e){
$this->error = $e->getMessage();
throw $e;
}
}
public function query($query) {
try {
$this->stmt = $this->dbh->prepare($query);
}
catch(PDOException $e){
$this->error = $e->getMessage();
throw $e;
}
}
public function execute(){
try {
return $this->stmt->execute();
}
catch(PDOException $e){
$this->error = $e->getMessage();
throw $e;
}
}
}

Sorry I derped. the value I passed in was $Product_area_id and the one I used is $product_area_id. god.

Related

Post not working in form with checkbox

I'm having a bit of trouble with the OOP CRUD method. My POST method is not retrieving or posting data to the DB. And I'm not sure where to look since it does not give any errors to display.
The logic above the form:
$id = $_GET['id'];
//Add Board
$b = new Board();
$userID = $_SESSION['id'];
$boards= $b->loadBoards($userID);
if(isset($_POST['addBoard'])){
try{
$sB = new Board();
$postID = 61;
$boardID = 1;
$sBoard = $sB->savePostToBoard($postID, $boardID);
} catch (Exception $e) {
$error = $e->getMessage();
}
}
This is the form:
<form method="post">
<div class="btn-group" data-toggle="buttons">
<?php foreach($boards as $key) : ?>
<label class="btn btn-primary active">
<input type="radio" name="option[]"value="
<?php echo $key['boardID'];?>">
<?php echo $key['boardTitle']; ?></label>
<?php endforeach ?>
<input class="btn btn-danger"type="submit" value="Toevoegen"
id="addBoard" name="addBoard">
</div>
</form>
And the class function:
public function getConnection() {
$conn = Db::getInstance();
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $conn;
}
private function getInputParameterDataType($value) {
$dataType = PDO::PARAM_STR;
if (is_int($value)) {
$dataType = PDO::PARAM_INT;
} elseif (is_bool($value)) {
$dataType = PDO::PARAM_BOOL;
}
return $dataType;
}
public function savePostToBoard($postID, $boardID)
{
$sql ="UPDATE board SET postID=:". $postID . " WHERE boardID=:boardID";
$statement = $this->getConnection()->prepare($sql);
$statement->bindValue(":boardID",$boardID, $this-
>getInputParameterDataType($boardID));
$statement->bindValue(":postID", $postid);
return $statement->execute();
}
Any feedback is highly appreciated, thanks for taking the time.
Kind regards
*) All your radio buttons have the same id attribute. It should be unique.
*) Give the id "addBoard" to the submit button.
*) Why do you use POST and GET?
$boardID = $_POST['option'];
$postID = $_GET['id'];
*) You missed the $ sign in statement->bindValue(":boardID",boardID);!
*) Posted data type should correspond to db data type. Use a third parameter in bindValue() to define the corresponding data type. And use a function:
private function getInputParameterDataType($value) {
$dataType = PDO::PARAM_STR;
if (is_int($value)) {
$dataType = PDO::PARAM_INT;
} elseif (is_bool($value)) {
$dataType = PDO::PARAM_BOOL;
}
return $dataType;
}
And then call like this:
$statement->bindValue(":boardID",$boardID, $this->getInputParameterDataType($boardID));
*) PDO::prepare() can throw a PDOException OR the value FALSE. So you should handle both cases. I wrote an answer about this: My answer for exception handling of prepare() & execute().
*) Have you made some changes until now? Works everything, or not yet?
Ok, I'll study it now.
Solutions for the new code:
*) Don't use semicolon ";" at the end of sql statements.
*) Update should have this form:
UPDATE [table-name] SET [col1]=:[col1],[col2]=:[col2] WHERE [PK-name]=:[PK-name]
*) For readability: pass the sql statement in a variable and use points to delimit used variables in it. Like:
$sql = "UPDATE board SET postID=:" . $postid . " WHERE boardID=:boardID"
$statement = $conn->prepare($sql);
*) As #teresko reminded you: you didn't pass $boardID to savePostToBoard():
$sBoard = $sB->savePostToBoard($postID, $boardID);
public function savePostToBoard($postID, $boardID) {...}
*) Use either $postID or $postid overall. Right now you are using both forms. Make a choice.
It should work now. Let me know.
Some recommandations:
*) Let your methods do only one thing (if possible). In your question, the connection creation doesn't belong in the method. If you call 20 methods which require a connection, then you have to write the same connection creation code in each of them. In your case, better define a getConnection() method in the Board class.
public function getConnection() {
$conn = Db::getInstance();
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $conn;
}
And now you have only this in your savePostOnBoard() by calling it:
public function savePostToBoard($postID) {
$statement = $this->getConnection()->prepare(...);
//...
}
*) In general, it's better to use the constructor for passing the variables used later by the methods. That's the role of the constructor: to initialize, e.g to give initial values to the object properties on creation. Example:
class Auto {
private $color;
private $doors;
private $airConditioning;
public __function __construct($color = 'blue', $doors = 3, $airConditioning = true) {
$this->color = $color;
$this->doors = $doors;
$this->airConditioning = $airConditioning;
}
}
$myAuto = new Auto('red', 4, false);
$hisAuto = new Auto('yellow', 8, true);
Oh, and always give easy-to-follow names to variables, functions, classes, etc. In your case, the upper phrase and this one would apply, for example, like this:
$board = new Board($boardID);
$boardUpdated = $board->update($postID);
See? Nicer names, more logical (following our real-world perception) arrangement of the arguments.
*) I would also recommend you to split your code in methods. This way you achieve a better reusability of code pieces and an elegant, easy-to-follow structure. Maybe something like this in analogy with your code:
public function savePostToBoard($postID, $boardID) {
$sql = "UPDATE board SET postID=:" . $postID . " WHERE boardID=:boardID";
$bindings = array(
':postID' => $postID,
':boardID' => $boardID
);
$statement = $this->execute($sql, $bindings);
return $statement->rowCount();
}
protected function execute($sql, array $bindings = array()) {
$statement = $this->prepareStatement($sql);
$this->bindInputParameters($statement, $bindings);
$this->executePreparedStatement($statement);
return $statement;
}
private function prepareStatement($sql) {
$statement = $this->getConnection()->prepare($sql);
return $statement;
}
private function bindInputParameters($statement, $bindings) {
foreach ($bindings as $key => $value) {
$statement->bindValue(
$this->getInputParameterName($key)
, $value
, $this->getInputParameterDataType($value)
);
}
return $this;
}
private function getInputParameterName($key) {
if (is_int($key)) {
return $key + 1;
}
$trimmed = ltrim($key, ':');
return ':' . $trimmed;
}
private function getInputParameterDataType($value) {
$dataType = PDO::PARAM_STR;
if (is_int($value)) {
$dataType = PDO::PARAM_INT;
} elseif (is_bool($value)) {
$dataType = PDO::PARAM_BOOL;
}
return $dataType;
}
private function executePreparedStatement($statement) {
$statement->execute();
return $this;
}
Good luck with your project!
You really should use these in your PDO instantiation:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Then you would have seen the syntax error in your query:
for some reason you have VALUES (:postID;) (notice the semicolon).
Also, you are not actually passing $boardID to the savePostToBoard() method at any point. You should add a second prarameter in that method.
As for your general application structure, you really should avoid using singletons to share the database connection and you should separate the domain logic from the persistence logic. Reading this post might be beneficial for you.

PDO PHP Update Script not working

I've searched on stackoverflow and other sources but I cant seem to find the issue that is preventing my PHP script from working.
Look at the echo_sql. It produces a healthy update statement which when run updates the database with no problem. Here is a sample:
update waste set waste_name=1 where id =82;
However, when the script is run, it does not apply changes to the database. Here is the script:
if ($_SERVER['REQUEST_METHOD'] == "POST") {
try {
$waste_id = $_POST['waste_id'];
$sql = new db;
$sql->beginTransaction();
$waste_name = $_POST['waste_name'];
$sql->query("update waste set waste_name=:waste_name where id =:waste_id;");
$echo_sql = "update waste set waste_name=$waste_name where id =$waste_id;";
echo $echo_sql;
$sql->bind(':waste_name', $waste_name);
$sql->execute();
$sql->endTransaction();
} catch (Exception $e) {
$sql->rollBack();
echo "Failed: " . $e->getMessage();
}
}
Additional details:
errorCode() = 00000
DB Class:
class db
{
private $stmt;
private $dbc;
public function __construct()
{
$u = "root";
$p = "";
try {
$this->dbc = new PDO('mysql:host=127.0.0.1;dbname=wimsdb', $u, $p);
$this->dbc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
$e->getMessage();
}
}
public function bind($param, $value, $type = NULL)
{
$this->stmt->bindParam($param, $value, $type);
}
public function beginTransaction()
{
return $this->dbc->beginTransaction();
}
public function rollBack()
{
return $this->dbc->rollBack();
}
public function endTransaction()
{
return $this->dbc->commit();
}
public function cancelTransaction()
{
return $this->dbc->rollBack();
}
public function execute()
{
try {
return $this->stmt->execute();
} catch (PDOException $e) {
return $e->errorInfo;
}
}
public function errorCode()
{
return $this->stmt->errorCode();
}
public function query($query)
{
$this->stmt = $this->dbc->prepare($query);
}
}
Please offer your suggestions on how this could be resolved.
You need to bind the :waste_id too:
$waste_id = $_POST['waste_id'];
$sql = new db;
$sql->beginTransaction();
$waste_name = $_POST['waste_name'];
$sql->query("update waste set waste_name=:waste_name where id =:waste_id;");
$sql->bind(':waste_name', $waste_name);
$sql->bind(':waste_id', $waste_id);
Any time you have an issue like this your error checking should return a meaningful message letting you know where the error is and likely what the error is. You should be able to check your error logs for details and/or output them to your screen during testing.
Add waste_id. To avoid missing parameters, I like putting the parameteers into the execute method. The bind method could be defined anywhere in the code so I had to look through your code and make sure waste_id binding wasn't defined somewhere else. When it's in the execute method, you can quickly see all parameters being defined there...it's also a tad more concise...but both have their uses.
if ($_SERVER['REQUEST_METHOD'] == "POST") {
try {
$waste_id = $_POST['waste_id'];
$sql = new db;
$sql->beginTransaction();
$waste_name = $_POST['waste_name'];
$sql->query("update waste set waste_name=:waste_name where id =:waste_id;");
$echo_sql = "update waste set waste_name=$waste_name where id =$waste_id;";
echo $echo_sql;
//just because I like this syntax for being concise and clear :)
$sql->execute(array(
'waste_id' => $waste_id,
'waste_name' => $waste_name
));
$sql->endTransaction();
} catch (Exception $e) {
$sql->rollBack();
echo "Failed: " . $e->getMessage();
}

Error handling prepared statements in a production environment

In a production environment when using prepared statements and all other validation is done, do I need to error check every every step of the way or can I just check end result of $stmt for true or false?
I am trying to clean up about 2000 lines of a function file and a lot of it just seems like wasted space when there is so much validation already done(ie checking for empty values, required values, empty fields etc).
Here is a rough, extremely simple, example of what I would like to do.
$sql = "SELECT count(*) FROM foo WHERE somecol = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s",$value);
$stmt->execute();
$stmt->bind_result($c);
$stmt->fetch();
if(false === $stmt){
//My error report
trigger_error("Something bad happened!" );
//Error user sees
$userErrorMsg[] 'Some generic msg here';
}
EDIT: I probably should have mention the $conn has been checked previously.
You have to decide if it's necessary in your case or not. But some programmers would say, that the code to catch an error is almost that much like the normal code.
In short: If there can be an error CATCH IT ;)
Otherwise I would recommend you to create a Wrapper class for your DB functions.
Just a small example to point you in the right direction:
class MyDBClass {
private static $con = null;
private static $instance = null;
public static function getInstance() {
if( null === self::$instance) {
// add error handling ;)
self::$instance = new MyDBClass();
self::$instance->setConnection();
}
return self::$instance;
}
private function setConnection() {
if( null === self::$con) {
// add error handling ;)
self::$con = mysqli_connect("localhost","my_user","my_password","my_db");
}
}
private function __construct() {}
public function select( $tableName, $columns = "*", $conditions = array(), $numRows = null ) {
// add your stuff with error handling
}
public function selectRow( $tableName, $columns = "*" , $conditions = array() ) {
// add your stuff with error handling
}
}
// use of class
$db = MyDBClass::getInstance();
$db->select( "mytable" );// would (for example) select * from mytable
NOTE: This is not a working example and I would recommend to get use a good framework or a small wrapper class

PDO and PHP OOP Code Advice

I am very new to PHP Object Orientated Programming so was wondering if I could get some good advice on a database object I created.
I call the class db and include my class into every page load and initiate the database object using $db = new db. I then call the method inside this for each action I may need (building a menu from the database, getting login information etc.) with different parameters depending on what it is i want to do.
It takes its first parameter as the query with the ? symbol as replacements for values I want to bind, the second parameter is the values to bind to it in an array that is then looped through inside the prepared_statement method and the third parameter is the type ( FETCH_ARRAY returns an array of a SELECT statements rows, NUM_ROWS returns the amount of rows affected and INSERT returns the last inserted ID).
An example of how I would call this function is below:
$db->prepared_execute( "SELECT * FROM whatever WHERE ? = ? ", array( 'password', 'letmein' ), NUM_ROWS );
The second and third parameters are optional for if there are no parameters to be bound or no return is needed.
As I am new to OOP I am finding it hard to get my head around exactly when to use correctly and what are public, private, static functions/variables and design patterns (Singleton etc.).
I've read many tutorials to get as far as I hav but I feel now I need to take it here to get further answers or advice on where to go next with OOP and with this class I've built.
It works as it is which for me is a good starting place except for any error handling which I will add in next but I want to make sure I am not making any obvious design errors here.
The code for the class is below:
class db {
var $pdo;
public function __construct() {
$this->pdo = new PDO('mysql:dbname=' . DB_NAME . ';host=' . DB_HOST . ';charset=utf8', DB_USER, DB_PASS);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function prepared_execute( $query, $bind_values = null, $type = null ) {
$preparedStatement = $this->pdo->prepare( $query );
if( $bind_values ) {
$i = 1;
foreach( $bind_values as $bind_value ) {
$preparedStatement->bindValue($i, $bind_value);
$i++;
} }
$preparedStatement->execute();
if( $type == FETCH_ARRAY ) { return $preparedStatement->fetchAll(); }
elseif( $type == NUM_ROWS ) { return $preparedStatement->rowCount(); }
elseif( $type == INSERT ) { return $this->pdo->lastInsertId(); }
else{ return true; }
}
Your code is a bit outdated. You should use one of the visibility keywords instead of var to declare your properties. In this case you probably want to use protected so that it cant be modified from outside the class but so that any future sub classes can modify it internally. Youll also probably want to add a getter in-case you need to work with PDO directly (which you will - see my final statements below my class example).
Its bad to hard code you PDO connection information in the class. You should pass these in as parameters same as you would if using PDO directly. I would also add the ability to pass in a pre-configured PDO instance as well.
While not required, its a good idea to conform to PSR-0 through PSR-2; Sepcifically in your case im speaking about Class and method naming which should both be camelCase and the first char of the class should be capital. Related to this your code formatting is also ugly particularly your block statements... If thats jsut an issue with copy and paste then ignore that comment.
So overall i would refactor your code to look something like this:
class Db {
protected $pdo;
public function __construct($dsn, $user, $pass, $options = array()) {
if($dsn instanceof PDO) {
// support passing in a PDO instance directly
$this->pdo = $dsn;
} else {
if(is_array($dsn)) {
// array format
if(!empty($options)) {
$dsn['options'] = $options;
}
$dsn = $this->buildDsn($options);
} else {
// string DSN but we need to append connection string options
if(!empty($options)) {
$dsn = $this->buildDsn(array('dsn' => $dsn, 'options' => $options));
}
}
// otherwise just use the string dsn
// ans create PDO
$this->pdo = new PDO($dsn, $user, $pass);
}
// set PDO attributes
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function getConnection()
{
return $this->pdo;
}
protected function buildDsn($options) {
if($isDbParts = isset($options['dbname'], $options['hostname']) || !($isDsn = isset($option['dsn']))) {
throw new Exception('A dsn OR dbname and hostname are required');
}
if($isDsn === true) {
$dsn = $options['dsn'];
} else if {
$format = '%s:dbname=%s;host=%s';
$driver = isset($options['dbtype']) ? $options['dbtype'] : 'mysql';
$dsn = sprintf($format, $options['dbtype'], $options['dbname'], $options['host']);
}
if(isset($options['options'])) {
$opts = array();
foreach($options['options'] as $name => $value) {
$opts[] = $name . '=' . $value;
}
if(!empty($opts)) {
$dsn .= ';' . implode(';', $opts);
}
}
return $dsn;
}
public function preparedExecute( $query, $bind_values = null, $type = null ) {
$preparedStatement = $this->pdo->prepare( $query );
if( $bind_values ) {
$i = 1;
foreach( $bind_values as $bind_value ) {
$preparedStatement->bindValue($i, $bind_value);
$i++;
}
}
$preparedStatement->execute();
if( $type == FETCH_ARRAY ) {
return $preparedStatement->fetchAll();
}
elseif( $type == NUM_ROWS ) {
return $preparedStatement->rowCount();
}
elseif( $type == INSERT ) {
return $this->pdo->lastInsertId();
}
else {
return true;
}
}
}
Lastly, unless this is just for educational purposes I wouldnt do this. There are a ton of different queries that have varying part assemblies which arent considered here so at some point this is not going to support what you need it to do. Instead i would use Doctrine DBAL, Zend_Db or something similar that is going to support greater query complexity through its API. In short, dont reinvent the wheel.
I have developed something similar and it can helps you.
public function select($sql, $array = array(), $fetchMode = PDO::FETCH_ASSOC){
$stmt = $this->prepare($sql);
foreach ($array as $key => $value){
$stmt->bindValue("$key", $value);
}
$stmt->execute();
return $stmt->fetchAll();
}
public function insert($table, $data){
ksort($data);
$fieldNames = implode('`,`', array_keys($data));
$fieldValues = ':' .implode(', :', array_keys($data));
$sql = "INSERT INTO $table (`$fieldNames`) VALUES ($fieldValues)";
$stmt = $this->prepare($sql);
foreach ($data as $key => $value){
$stmt->bindValue(":$key", $value);
}
$stmt->execute();
}

Database Error:00' for column 'date' at row 1

I have just finished installing anchor-cms but when I go to view the admin page or the homepage I get the following output
Unhandled Exception
Message:
Database Error:00' for column 'date' at row 1
SQL: INSERT INTO `sessions` (`id`, `date`, `data`) values (?, ?, ?)
Location:
/Library/WebServer/Documents/anchor/system/database/connection.php on line 128
Stack Trace:
#0 /Library/WebServer/Documents/anchor/system/database/query.php(254): System\Database\Connection->execute('INSERT INTO `se...', Array)
#1 /Library/WebServer/Documents/anchor/system/session/database.php(42): System\Database\Query->insert(Array)
#2 /Library/WebServer/Documents/anchor/system/session/payload.php(78): System\Session\Database->save(Array, Array, false)
#3 [internal function]: System\Session\Payload->save()
#4 /Library/WebServer/Documents/anchor/system/session.php(58): call_user_func_array(Array, Array)
#5 /Library/WebServer/Documents/anchor/system/bootstrap.php(124): System\Session::__callStatic('save', Array)
#6 /Library/WebServer/Documents/anchor/system/bootstrap.php(124): System\Session::save()
#7 /Library/WebServer/Documents/anchor/index.php(33): require('/Library/WebSer...')
#8 {main}
Here is my connection.php file
<?php namespace System\Database;
/**
* Nano
*
* Lightweight php framework
*
* #package nano
* #author k. wilson
* #link http://madebykieron.co.uk
*/
use System\Config;
use PDO, PDOStatement, PDOException, Exception;
class Connection {
public $pdo, $config, $queries = array();
public function __construct(PDO $pdo, $config) {
$this->pdo = $pdo;
$this->config = $config;
}
public function transaction($callback) {
$this->pdo->beginTransaction();
// After beginning the database transaction, we will call the callback
// so that it can do its database work. If an exception occurs we'll
// rollback the transaction and re-throw back to the developer.
try {
call_user_func($callback);
}
catch(PDOException $e) {
$this->pdo->rollBack();
throw $e;
}
$this->pdo->commit();
}
public function query($sql, $bindings = array()) {
$sql = trim($sql);
list($statement, $result) = $this->execute($sql, $bindings);
// The result we return depends on the type of query executed against the
// database. On SELECT clauses, we will return the result set, for update
// and deletes we will return the affected row count.
if(stripos($sql, 'select') === 0 or stripos($sql, 'show') === 0) {
return $this->fetch($statement, Config::get('database.fetch'));
}
elseif(stripos($sql, 'update') === 0 or stripos($sql, 'delete') === 0) {
return $statement->rowCount();
}
// For insert statements that use the "returning" clause, which is allowed
// by database systems such as Postgres, we need to actually return the
// real query result so the consumer can get the ID.
elseif (stripos($sql, 'insert') === 0 and stripos($sql, 'returning') !== false) {
return $this->fetch($statement, Config::get('database.fetch'));
}
else {
return $result;
}
}
public function first($sql, $bindings = array()) {
list($statement, $result) = $this->execute($sql, $bindings);
if($result) return $statement->fetch(Config::get('database.fetch'));
}
public function column($sql, $bindings = array()) {
list($statement, $result) = $this->execute($sql, $bindings);
if($result) return $statement->fetchColumn();
}
public function type($var) {
if(is_null($var)) {
return PDO::PARAM_NULL;
}
if(is_int($var)) {
return PDO::PARAM_INT;
}
if(is_bool($var)) {
return PDO::PARAM_BOOL;
}
return PDO::PARAM_STR;
}
public function execute($sql, $bindings = array()) {
// Each database operation is wrapped in a try / catch so we can wrap
// any database exceptions in our custom exception class, which will
// set the message to include the SQL and query bindings.
try {
$statement = $this->pdo->prepare($sql);
// bind paramaters by data type
// test key to see if we have to bump the index by one
$zerobased = (strpos(key($bindings), ':') === 0) ? false : true;
foreach($bindings as $index => $bind) {
$key = $zerobased ? ($index + 1) : $index;
$statement->bindValue($key, $bind, $this->type($bind));
}
$start = microtime(true);
$result = $statement->execute();
$this->queries[] = array($statement->queryString, $bindings);
}
// If an exception occurs, we'll pass it into our custom exception
// and set the message to include the SQL and query bindings so
// debugging is much easier on the developer.
catch(PDOException $exception) {
$message = explode(':', $exception->getMessage());
$error = '<strong>Database Error:</strong>' . end($message) . str_repeat("\n", 3) .
'<strong>SQL: </strong>' . $sql;
$exception = new Exception($error, 0, $exception);
throw $exception;
}
return array($statement, $result);
}
protected function fetch($statement, $style) {
// If the fetch style is "class", we'll hydrate an array of PHP
// stdClass objects as generic containers for the query rows,
// otherwise we'll just use the fetch style value.
if($style === PDO::FETCH_CLASS) {
return $statement->fetchAll(PDO::FETCH_CLASS, 'stdClass');
}
else {
return $statement->fetchAll($style);
}
}
}
Second Error
Database Error: Invalid datetime format: 1292 Incorrect datetime value: '2013-02-19T06:47:59+00:00' for column 'date' at row 1
Disclaimer: technically this is not an answer ;)
Apparently the anchor-CMS uses the ISO 8601-format to store (at least) the session-date, which is apparently not safe to use, especially when the "strict mode" is active!
I think for the moment it's probably the best to disable the strict mode of MySQL. If you don't "own" the SQL-Server you can disable the strict mode for a single session.
You can do that by editing system/database.php starting at line 51. Change the following lines from
if(version_compare(PHP_VERSION, '5.3.6', '<=')) {
$options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $config['charset'];
}
to
if(version_compare(PHP_VERSION, '5.3.6', '<=')) {
$options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $config['charset']
. ', sql_mode=\'ALLOW_INVALID_DATES\'';
} else {
$options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET sql_mode=\'ALLOW_INVALID_DATES\'';
}
I think that should work until anchor-CMS uses the correct dates (I probably make a pull-request for that this evening after work).

Categories