I'm trying to place these in a seperate file that'll be included on every page
$sql = 'select id, name, age, address, pincode from json where name = :name';
$arr = array(":name" => $name);
// There are some 30 diff sql's and arrays
Another page
$name = 'peter';
$conn = connect();
function myType(){
global $conn;
global $sql;
global $arr;
$stmt = $conn->prepare($sql);
$stmt->execute($arr);
while( $row = $stmt->fetch(PDO::FETCH_ASSOC) ) {
foreach ($row as $value) {
echo $value.' <br>';
}
}
}
myType();
I'm trying to keep the sqls and arrays in a separate file and use them when needed. Keeps things clean and easy to maintain. But the variables are declared later, which gives me: Notice: Undefined variable: name in C:\web\apache\htdocs\dev\json.php on line 24
Can you see a way to do this without uglying things?
Well you should use two files
sql.php
fetch.php
Then in fetch.php you will use require_once 'sql.php'
here's the code for fetch.php:
$name = 'peter';
$conn = connect();
require_once 'sql.php';
function myType(){
global $conn;
global $sql;
global $arr;
$stmt = $conn->prepare($sql);
$stmt->execute($arr);
while( $row = $stmt->fetch(PDO::FETCH_ASSOC) ) {
foreach ($row as $value) {
echo $value.' <br>';
}
}
}
myType();
And this is sql.php
$sql = 'select id, name, age, address, pincode from json where name = :name';
$arr = array(":name" => $name);
This should be helpful and you can use sql.php whenever you like.
Storing the queries and there bound parameters in a separate include is a bit strange. How will you change the bound parameter after the include?
My suggestion is to create a model that will handle the database operations. The benefit of this is you can encapsulate the database work and keep it separate from your app logic and also easily reuse it throughout.
Basic example:
class CustomersModel
{
protected $db;
public function __construct($db)
{
$this->db = $db;
}
public function getByName($name)
{
$result = array();
$sql = 'select id, name, age, address, pincode from json where name = :name';
if($stmt = $conn->prepare($sql))
{
$stmt->execute(array(":name" => $name));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
return $result;
}
}
Usage:
require_once('/path/to/CustomerModel.php');
$conn = connect();
$model = new CustomerModel($conn);
$customers = $model->getByName('peter');
foreach($customers as $c)
{
echo htmlspecialchars($c['name']) . '<br />;
}
Related
Iam trying to make a OOP based forum in PHP and currently im stuck at making the Database class. Specifically Iam stuck at making a "general purpose" insert class function for the Datatable class (using PDO btw).
class DB
{
private $dbconn;
public function __construct(){
}
protected function connect($dbname, $dbhost='127.0.0.1', $dbuser='root', $dbpass=''){
try{
$this->dbconn = new PDO("mysql:host=$dbhost;dbname=$dbname;", $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
}
catch(PDOException $e){
echo 'Connection failed: '.$e->getMessage()."<br />";
}
}
protected function disconnect(){
$this->dbconn = null;
}
public function insert($dbname, ){
$this->connect($dbname);
try{
# prepare
$sql = "INSERT INTO pdodemotable (firstname, lastname, age, reg_date)
VALUES (?, ?, ?, now())";
$stmt = $dbconn->prepare($sql);
# the data we want to insert
$data = array($firstname, $lastname, $age);
# execute width array-parameter
$stmt->execute($data);
echo "New record created successfully";
}
catch(PDOException $e){
echo $sql . "<br>" . $e->getMessage();
}
}
}
The insert function is as you see unfinished. I cant figure out how to get the insert function to adapt to ANY amount of arguments, ANY amount of database columns and ANY table. The code thats in the function right now is taken from one of my other projects where I used procedural programming. Its by first time using OOP with Databases.
Im a newbie to both OOP and PDO. There must be some sort of method or function that could help me that Im missing. The only solution I see right now is to use a ridicoulus amount of string handling and if statement... it cant be the best solution... there must be a easier way...
First notice - you don't need the $dbname parameter for insert method, instead it should be a constructor parameter:
class DB {
private $dbconn;
public function __construct($dbname, $dbhost='127.0.0.1', $dbuser='root', $dbpass='') {
// also don't catch the error here, let it propagate, you will clearly see
// what happend from the original exception message
$this->dbconn = new PDO("mysql:host=$dbhost;dbname=$dbname;", $dbuser, $dbpass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"));
}
...
}
As for the insert method - first try to imagine how it will be used.
For example, it can be like this:
$db = new DB('mydb');
$db->insert('mytable', array('firstname'=>'Pete', 'lastname'=>'Smith'));
Then you can pass the table name and data (keys/values) into the method:
public function insert($table, $data) {
// again, no need to try / catch here, let the exceptions
// do their job
// handle errors only in the case you are going to fix them
// and not just to ingnore them and 'echo', this can lead to much worse problems
// see the explanation below regarding the `backtick` method
$table = $this->backtick($table);
$fields = array();
$placeholders = array();
$values = array();
foreach($data as $key=>$value) {
$fields[] = $this->backtick($key);
// you can also process some special values like 'now()' here
$placeholders[] = '?';
}
$fields = implode($fields, ','); // firstname, lastname
$placeholders = implode($placeholders, ','); // ?, ?
$sql = "INSERT INTO $table ($fields) values ($placeholders)";
$stmt = $this->dbconn->prepare($sql);
$stmt->execute(array_values($data));
}
public function update($table, $id, $data) {
$table = $this->backtick($table);
$fields = array();
foreach($data as $key=>$value) {
$fields[] = $this->backtick($key) . " = ?";
}
$fields = implode($fields, ','); // firstname=?, lastname=?
$sql = "UPDATE $table SET $fields where id=?";
$stmt = $this->dbconn->prepare($sql);
$data['id'] = $id;
$stmt->execute(array_values($data));
if ($stmt->execute(array_values($data)) === false) {
print 'Error: ' . json_encode($stmt->errorInfo()). PHP_EOL;
}
while ($row = $stmt->fetchAll()) {
print json_encode($row) . PHP_EOL;
}
}
private function backtick($key) {
return "`".str_replace("`","``",$key)."`";
}
Another alternative is to create the separate object which will represent one table row (the ActiveRecord pattern).
The code which uses such object could look like this:
$person = new Person($db);
$person->firstName = 'Pete';
$person->lastName = 'Smith';
$person->save(); // insert or update the table row
Update on possible SQL injection vulnerability
I also added the update and backtick methods to illustrate the possible SQL injection.
Without the backtick, it is possible that update will be called with something like this:
$db->updateUnsafe('users', 2, array(
"name=(SELECT'bad guy')WHERE`id`=1#"=>'',
'name'=>'user2', 'password'=>'text'));
Which will lead to the SQL statement like this:
UPDATE users SET name=(SELECT'bad guy')WHERE`id`=1# = ?,name = ?,password = ? where id=?
So instead of updating the data for user with id 2, we it will change the name for the user with id 1.
Due to backtick method, the statement above will fail with Unknown column 'name=(SELECT'bad guy')WHEREid=2#' in 'field list'.
Here is the full code of my test.
Anyway, this probably will not protect you from any possible SQL injection, so the it is much better not to use the user input for known parameters like table name and field names.
Instead of doing something like $db->insert('mytable', $_POST), do $db->insert('mytable', array('first'=>$_POST['first'])).
Try to pass the arguments has an array, then, inside the method insert, do a foreach.
Something like:
$data['first_name'] = 'your name';
...
$data['twentieth_name'] = 'twentieth name';
foreach( $data as $key => $value )
$final_array[':'.$key] = $value;
$stmt->execute( $final_array );
unable to delete i row using PDO in php. Here is my code given below
this is inc.common.php
<?php
#session_start();
include_once '../common/inc.config.php';
include_once '../common/inc.globalConstants.php';
$db = new PDO("mysql:host=$mdbhost;dbname=$mdbname",$mdbuser,$mdbpass );
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
include_once '../classes/cls.common.php';
$Cobj=new common($db);
?>
this my cls.class.php
<?php
class common {
public function common($dbcon) {
$this->dbCon = $dbcon;
}
public function getCustomData($tableName,$fields, $conditions = "") {
$stmt = "";
$sql = "";
$sql = "SELECT $fields FROM $tableName $conditions ";
$stmt = $this->dbCon->query($sql);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
public function delet($tableName, $class_id){
$inputArray['classId']=$class_id;
$count = $this->$dbCon->prepare("DELETE FROM $tableName WHERE classId =:classId");
$result = $stmt->execute($inputArray);
return $result;
}
?>
this is my addinfo.php
<?php
include '../common/inc.common.php';
$class_id=$_POST['refid'];
if(isset($_POST['mode']))
{
$tableName="class";
$class_id=$_POST['refid'];
$res=$Cobj->delet($tableName, $class_id);
}
?>
on passing variables using AJAX call i couldn't able to delete the row .Ajax call is success . only problem with PDO delete.
$.ajax({
url: "../masters/addinfo.php",
type: "POST",
data:"refid="+class_id+"&mode=delete",
});
my class table has 4 fields classId,name,date,stat.
The $stmt variable in function delet() is not defined.
public function delet($tableName, $class_id){
$inputArray['classId']=$class_id;
$stmt = $this->$dbCon->prepare("DELETE FROM $tableName WHERE classId =:classId");
$result = $stmt->execute($inputArray);
return $result;
}
Will fix this. Note what changed; $count changed to $stmt
I get this error when trying to run this, what do it mean?
if(isset($_POST['submit']))
{
$date = $_POST['date'];
$partySize = $_POST['partysize'];
$catering = $_POST['catering'];
print_r($date);
print_r($partySize);
print_r($catering);
include "/diska/www/include/coa123-13-connect.php";
$host='co-project.lboro.ac.uk';
$dbName='coa123wdb';
$dsn = "mysql://$username1:$password1#$host/$dbName"; //Data Source Name
require_once('MDB2.php'); //Just include this line into your program - you do not have to have the source in your directory
$db =& MDB2::connect($dsn); //Try to make a connection
if (PEAR::isError($db)) {
die($db->getMessage());
}
//step 1 - query
$sql = "SELECT * FROM venue
WHERE capacity >= $partySize";
//step 2 - executing the query
$result =& $db->query($sql);
if (PEAR::isError($sql)) {
die($result->getMessage());
}
$valueIDArray = array();
while($row = $result -> fetchrow()){
$valueIDArray[] = $row[0];
}
$values = implode(',', $valueIDArray);
$query = "SELECT * FROM venue_booking
WHERE venue_id IN ($values)";
//step 2 - executing the query
$result1 =& $db->query($query);
if (PEAR::isError($query)) {
die($result1->getMessage());
}
while($row = $result1 -> fetchrow()){
$idValue[] = $row[0];
$dateValues[] = $row[1];
}
availableDate($dateValues,$date,$idValue, $db); //Line error points to
function availableDate($bookedDates, $date, $idValue, $db){
I have commeted on the line the error points to, this file works when its in its own PHP file but when inside the if(isset($_POST['submit'])) statement it does not work. What am I doing wrong?
Move the function definition outside the if statement. There's almost never a good reason to do that -- the only excuse might be if you wanted different definitions of the function depending on a condition, but that doesn't seem to be what you're doing. If you define a function inside an if, you have to define it before you call it; functions defined at top-level can be called from anywhere.
call availableDate after it's defined, if you already have to define it inside of if statement.
Ex.
function availableDate($bookedDates, $date, $idValue, $db){
...
}
//and then call it...
availableDate($dateValues,$date,$idValue, $db); //Line error points to
EDIT:
Example of non-working function defined inside of conditional statement
if(1){
func('a');
function func($a){
echo $a;
}
}
This wont work, but this will:
if(1){
function func($a){
echo $a;
}
func('a');
}
I'm trying to create a search feature on my website. It isn't showing any results and I keep getting Call to a member function prepare() on a non-object in line x...
function doSearch() {
$output = '';
if(isset($_POST['search'])) {
$searchq = $_POST['search'];
$searchq = preg_replace ("#[^0-9a-z]#i","",$searchq);
$sql = "SELECT * FROM entries WHERE name LIKE :searchq or description LIKE :searchq or content LIKE :searchq";
$stmt = $conn->prepare($sql);
$stmt->bindParam(":searchq",$searchq,PDO::PARAM_STR);
$stmt->execute();
$count = $stmt->rowCount();
if($count == 0) {
$output = '<tr><tr>No results found.</tr></td>';
} else {
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$eName = $row['name'];
$eDesc = $row['description'];
$eCont = $row['content'];
$id = $row['id'];
$elvl = $row['level'];
$ehp = $row['hp'];
$output .= '<tr><td>'.$eName.'</td><td>'.$eDesc.'</td><td>'.$elvl.'</td><td>'.$ehp.'</td></tr>';
}
}
return $output;
}
}
I have my PDO connection included in my functions.php file.
prepare() is a method of a PDO connection object, and your $conn variable is not one. It needs to be instantiated as a connection object, like this:
$conn = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
Or if that's already done somewhere in the "global" scope, you just need to declare in your function:
global $conn;
It's fine to do this. The declaration is misleading. It's only "global" in the scope of the executing script, and does not transcend the script execution. All such objects are destroyed at the end of script execution. It's nothing to do with the session.
should be like:
$sql = "SELECT * FROM entries
WHERE name LIKE :searchq or
description LIKE :searchq or
content LIKE :searchq";
global $conn;
$stmt = $conn->prepare($sql);
Make sure you have included the db configuration file.
I am selecting data from a database. The database field names are exactly the same as the class variable names. Is there a way to store this data into the class variables without specifying each one individually?
//gets info about a specified file.
//chosen based on a supplied $fileId
function getFileInfo($fileId)
{
//select info from database
$sql = "SELECT id, companyId, url, name, contentType, fileSize, saved, retrieved
FROM files
WHERE id = $fileId";
$results = $this->mysqli->query($sql);
$results = $results->fetch_object();
//store info into class variables
$this->id = $results->id;
$this->companyId = $results->companyId;
$this->url = $results->url;
$this->name = $results->name;
$this->contentType = $results->contentType;
$this->fileSize = $results->fileSize;
$this->saved = $results->saved;
$this->retrieved = $results->retrieved;
}
A quick and dirty way would ba a loop:
foreach($result as $var => $value) {
$this->$var = $value;
}
I'd propose this approach:
$nameMap = array(
'id',
'companyId',
'url',
'name',
'contentType',
'fileSize',
'saved',
'retrieved',
);
foreach( $nameMap as $attributeName ) {
$this->$attributeName = $results->$attributeName ;
}
While one could write
foreach($result as $var => $value) {
...
}
the outcome fully depends on backing table's structure. If you add further attributes to the table, your code might break.
Using $nameMap, the application still works.
Just use foreach structure:
foreach ($result as $column => $value) {
$this->$column = $value;
}
Not nice but will work.
Humm. Well, PDO has native functions for that, if you're not married to mysqli for some reason:
<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
$sth = $dbh->prepare("SELECT name, colour FROM fruit");
$sth->execute();
$result = $sth->fetch(PDO::FETCH_OBJ);
print $result->NAME;
The biggest disadvantage I've found is that PDO doesn't support SSL connections between the PHP machine and the MySQL machine.