I am trying to create a PHP array of random "fruits" from a database.
The database class that I am using:
class Db
{
private static $_instance = null;
private $_pdo;
private function __construct()
{
try {
$this->_pdo = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME .'', DB_USER, DB_PASS);
} catch (PDOException $e) {
die($e->getMessage());
}
}
public static function getInstance()
{
if (!isset(self::$_instance)) {
self::$_instance = new Db();
}
return self::$_instance;
}
public function prepare($sql)
{
return $this->_pdo->prepare($sql);
}
}
The class that is using the database to fetch "fruits" to create an array of a given size of random entries by using 3 seperate queries to calculate and retrieve "x" number of random items form the database.
class FruitBasket
{
private $_fruitArray = array(),
$_inputCode,
$_db;
public function __construct($input = null)
{
$this->_inputCode = $input;
$this->_db = Db::getInstance();
var_dump($this->_db);
}
public function pickFruit($count)
{
$doubleCount = $count * 2;//double the count used in calculation with the random number
$fruitIDs = ''; //the choosen fruits (id's)
$i = 0;
//#1 get total count of fruits table
$sql = "SELECT COUNT(*) FROM `fruits`";
if ($query = $this->_db->prepare($sql)) {
if ($query->execute()) {
$allFruits = $query->fetch(PDO::FETCH_NUM);
} else {
print_r("ERROR QUERY DID NOT EXECUTE #1");
}
} else {
print_r("ERROR CHECK SQL SYNTAX #1");
}
//#2 calculate random number to pull from all of id's
$sql = "SELECT id FROM `fruits` WHERE RAND()* ? < ? ORDER BY RAND() LIMIT 0, ? ";
if ($query = $this->_db->prepare($sql)) {
$query->bindParam(1, $allFruits[0], PDO::PARAM_INT);
$query->bindParam(2, $doubleCount, PDO::PARAM_INT);
$query->bindParam(3, $count, PDO::PARAM_INT);
if ($query->execute()) {
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
if ($i == 0) {
$fruitIDs .= "'" . $row['id'] . "'";
} else {
$fruitIDs .= ", '" . $row['id'] . "'";
}
$i++;
}
} else {
print_r("ERROR QUERY DID NOT EXECUTE #2");
}
} else {
print_r("ERROR CHECK SQL SYNTAX #2");
}
//#3 get the fruits
$sql="SELECT NAME FROM `fruits` WHERE `id` IN( ? )";
if ($query = $this->_db->prepare($sql)) {
$query->bindParam(1, $fruitIDs, PDO::PARAM_STR);
if ($query->execute()) {
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
$this->_fruitArray[] = $row['name'];
}
} else {
print_r("ERROR QUERY DID NOT EXECUTE #3");
}
} else {
print_r("ERROR CHECK SQL SYNTAX #3");
}
return $this->_fruitArray;
}
}
The table that I am attempting has a bunch of "fruits" in it, an example of how the table is structured:
==================================
| ID | NAME |
==================================
| 01 | Apple |
==================================
I am attempting to test this all out by using the following:
echo "<pre>";
echo "TESTING FRUIT ARRAY:</br></br>";
$basket = new FruitBasket();
echo"</br></br> PRINT_R: </br></br>";
print_r($basket->pickFruit(10));
echo "</br></br> VARDUMP: </br></br>";
var_dump($basket->pickFruit(10));
The sql query prepares and executes properly, I can do a vardump of the prepares and the binds and they return TRUE. Nothing is returned on the last query however.
In the first query that executes Doing a print statement of $allFruits shows the correct total count from the table.
The second query seems to be working properly,the string $fruitIDs, gets random id's from the table, I can echo this out and confirm that indeed the correct number of ID's are returned.
The problem occurs (I think) with the third query:
Nothing is returned form this query. The prepare statement returns true on a var dump as does the execute, however there is no results!
If I manually take the ID's that are output from query#2 and run it myself in mysql, the correct "fruit" names are returned.
Am I binding the variables incorrectly? I read the pages from the PHP manual but clearly I am doing something wrong.
Please help! :)
Thanks to the links and input provided by Your common sense, using the following:
Reference - frequently asked questions about PDO
and
Can I bind an array to an IN() condition?
I was able to resolve this by changing my query as follows:
//#2 calculate random number to pull from all of id's
$sql = "SELECT id FROM `fruits` WHERE RAND()* ? < ? ORDER BY RAND() LIMIT 0, ? ";
if ($query = $this->_db->prepare($sql)) {
$query->bindParam(1, $allFruits[0], PDO::PARAM_INT);
$query->bindParam(2, $doubleCount, PDO::PARAM_INT);
$query->bindParam(3, $count, PDO::PARAM_INT);
if ($query->execute()) {
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
$fruitIDs[] = $row['id'];
}
} else {
print_r("ERROR QUERY DID NOT EXECUTE #2"); }
} else {
print_r("ERROR CHECK SQL SYNTAX #2");
}
//#3 get the fruits
$inQuery = implode(',', array_fill(0, count($fruitIDs), '?'));
$sql="SELECT NAME FROM `fruits` WHERE `id` IN($inQuery)";
if ($query = $this->_db->prepare($sql)) {
if ($query->execute($fruitIDs)) {
while ($row = $query->fetch(PDO::FETCH_NUM)) {
$this->_fruitArray[] = $row[0];
}
} else {
print_r("ERROR QUERY DID NOT EXECUTE #3");
}
} else {
print_r("ERROR CHECK SQL SYNTAX #3");
}
return $this->_fruitArray;
}
I do not fully understand the security benefits or ramifications of binding the parameters or simply including them in the actual execute() but for now the query is performing as intended, so thank you for the input!
Related
I have this code
<?php
class Objekt{
// database connection and table name
private $conn;
private $table_name = "objects";
// object properties
public $id;
public $id_group;
public $title;
public $description;
public $lat;
public $lng;
public $icon;
public $tagsraw;
// constructor with $db as database connection
public function __construct($db){
$this->conn = $db;
}
function create(){
// query to insert record
$query = "INSERT INTO
" . $this->table_name . "
SET
id_group=:id_group, title=:title, description=:description, lat=:lat, lng=:lng, icon=:icon;
SELECT max(id) AS id FROM objects;";
// prepare query
$stmt = $this->conn->prepare($query);
// sanitize
$this->id_group=htmlspecialchars(strip_tags($this->id_group));
$this->title=htmlspecialchars(strip_tags($this->title));
$this->description=htmlspecialchars(strip_tags($this->description));
$this->lat=htmlspecialchars(strip_tags($this->lat));
$this->lng=htmlspecialchars(strip_tags($this->lng));
$this->icon=htmlspecialchars(strip_tags($this->icon));
// bind values
$stmt->bindParam(":id_group", $this->id_group);
$stmt->bindParam(":title", $this->title);
$stmt->bindParam(":description", $this->description);
$stmt->bindParam(":lat", $this->lat);
$stmt->bindParam(":lng", $this->lng);
$stmt->bindParam(":icon", $this->icon);
// execute query
if($stmt->execute()){
//$stmt->execute();
/*
ERROR below here
Uncaught PDOException: SQLSTATE[HY000]: General error
stack trace:
#0 PDOStatement ->fetch(2)
#1 Objekt->create()
*/
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$this->id = $result['id'];
echo "$this->id";
//get tags matches
$tags = [];
$this->tagsraw = preg_replace('/\s+/', '', $this->tagsraw);
$tags = explode(',', $this->tagsraw);
$id_tags = [];
for ($i = 0; $i < sizeof($tags); $i++) {
$query = "SELECT id FROM category WHERE title=" . tags[i];
$stmt = $this->conn->prepare($query);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_OBJ);
$id_tags[i] = $result->id;
}
for ($i = 0; $i < sizeof($id_tags); $i++) {
$query = "INSERT INTO category_object SET id_object=" . $this->id . ", id_category=" . $id_tags[i];
$stmt = $this->conn->prepare($query);
$stmt->execute();
}
return true;
}
return false;
}
What I want to do:
Insert Object and create a relation to a category_object table over foreign keys id_object / id_category
What I would like to improve:
What do I have to do to delete an insert if it fails (where should I put a try/catch or something else)
What is wrong with my fetch? I Select the value from max(id) to get the value of my inserted object, why is it throwing an Exception
I have another Warning why is it telling me that
for ($i = 0; $i < sizeof($id_tags); $i++) {
$query = "INSERT INTO category_object SET id_object=" . $this->id . ", id_category=" . $id_tags[i];
$stmt = $this->conn->prepare($query);
$stmt->execute();
}
will be deprecated in future php versions..
Use transactions.
Any insert/update/delete done within a transaction will not be actually executed against the database until you call commit(), and you can always roll back the changes, abandoning them in case of failure.
In your code, you should be OK with replacing if($stmt->execute()){ with
try {
$this->conn->beginTransaction();
$stmt->execute();
// ...everything else from inside the if statement here...
$this->conn->commit();
return true;
} catch (\Exception $e) {
$this->conn->rollback();
return false;
}
I have a function to search for records by course name:
<?php
function searchByCourse()
{
if (isset($_POST["course_title"])) {
//Copy to local var
$course_title = $_POST["course_title"];
$stmt = self::$conn->prepare("SELECT student_id, student_name, course_title FROM student_info WHERE course_title = ?");
$stmt->bind_param("s", $course_title);
$result = $stmt->execute();
if ($result === FALSE) {
$stmt->close();
return FALSE;
} else {
$results_array = array();
$stmt->bind_result($student_id, $student_name, $course_title_found);
while ($stmt->fetch()) {
echo "Fetch! \n";
$row = array();
$row["student_id"] = $student_id;
$row["student_name"] = $student_name;
$row["course_title"] = $course_title;
$results_array[] = $row;
}
$stmt->close();
return $results_array;
}
} else {
return FALSE;
}
}
?>
The code seems to execute fine but when I test it using curl for course_title=Computing it should return 3 results. However the echo "Fetch!" is never displayed. It seems to be that there is nothing for it to fetch. It's driving me a little crazy. I've checked all the var names in the database and they match up fine. Any ideas what I could be doing wrong here?
EDIT:
This method is part of my class DbHandler. $conn is a protected static MySqli connection object created in function__contruct().
called like this:
$db = new DbHandler();
$db->searchByCourse();
I have other database functions that work fine for this design pattern. The function is being called correctly. I have also checked the $_POST["course_title"] and that is being passed correctly.
Am trying to save the result of multiple check-boxes as separate records. my code is not functioning. please help!
<?php
session_start();
$id = $_SESSION['user_id'];
$db = new PDO('mysql:host=localhost;dbname=idp;charset=utf8','root', '');
foreach($_POST['comp'] as $val){
$tmp['user_id'] = $id;
$tmp['comp_id'] = $val;
$vars[] = $tmp;
}
$qry = "INSERT INTO compentency_result (user_id, result) VALUES (:user_id, :comp_id)";
try
{
$sql = $db->prepare($qry);
$numRows = 0;
foreach($vars as $insert){
$numRows += $sql->execute($insert);
}
print("<p>There were {$numRows} inserted into the database!</p>");
}
catch(PDOException $e)
{
print("<p>Oops! There was an issue - this is the message: {$e->getMessage()}</p>");
}
?>
The result is showing me that nothing is added to the database.
To bind the parameters individually you would do this:
try
{
$sql = $db->prepare($qry);
$numRows = 0;
foreach($vars as $insert){
$sql->bindParam(':user_id', $insert['user_id'], PDO::PARAM_STR);
$sql->bindParam(':comp_id', $insert['comp_id'], PDO::PARAM_STR);
$sql->execute();
$numRows += $sql->rowCount(); // get the rows affected this way
}
echo "<p>There were {$numRows} inserted into the database!</p>";
}
In addition, I added a more proper and reliable method of getting the affected rows, using rowCount().
If you don't want to bind the elements individually you can use execute() with an array as shown in Demystifying PDO
I'm newbie in PHP and WordPress. This approach was working fine for me in ASP.NET but here both queries are not working. When I comment the first one, the second one(Insertion) is working fine.
$dbhostname="111.1.11.111";
$dbusername="db_userName";
$dbpassword="mypassword";
$con=mysqli_connect($dbhostname,$dbusername,$dbpassword,"db_name");
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
Check wether the email exists or not ?
$sql="CALL Select_ConfirmEmailExistance('abc#abc.com')";
$containsResult=0;
if ($result=mysqli_query($con,$sql))
{
// Get field information for all fields
while ($fieldinfo=mysqli_fetch_assoc($result))
{
if (isset($fieldinfo)) {
$containsResult=1;// Email Exists
}
}
mysqli_free_result($result);
if ($containsResult==0) { // In case email does not exists enter it.
$sql="CALL insert_Userinfo('abc','def','abc#abc.com','mnop')";
if ($result=mysqli_query($con,$sql))
{
$data;
while ($fieldinfo=mysqli_fetch_assoc($result))
{
$data[]=$fieldinfo;
}
}
}
print_r($data);
}
mysqli_close($con);
First Store Procdure
BEGIN
SELECT 1 as emailstatus FROM userinfo WHERE email= p_email;
END
Second Stored Procedure
INSERT INTO `userinfo` (
`first_name`,
`last_name`,
`email`,
`password`
)
VALUES
(
`FName`,
`LName`,
`Email`,
`Pass`
);
SELECT
user_id
FROM
userinfo
ORDER BY
user_id DESC
LIMIT 1;
Here is what I was talking about when I said create a query class to fetch data. This is just a simple one, but it works pretty effectively and you can build it out to be pretty powerful.
class DBEngine
{
public $con;
public function __construct($host="111.1.11.111",$db = "dbname",$user="db_userName",$pass="mypassword")
{
try {
$this->con = new PDO("mysql:host=$host;dbname=$db",$user,$pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
}
catch (Exception $e) {
return 0;
}
}
// Simple fetch and return method
public function Fetch($_sql)
{
$query = $this->con->prepare($_sql);
$query->execute();
if($query->rowCount() > 0) {
while($rows = $query->fetch(PDO::FETCH_ASSOC)) {
$array[] = $rows;
}
}
return (isset($array) && $array !== 0 && !empty($array))? $array: 0;
}
// Simple write to db method
public function Write($_sql)
{
$query = $this->con->prepare($_sql);
$query->execute();
}
}
// Create an instance of the engine
$query = new DBEngine();
// Query 1 will return an array or false (0)
$call1 = $query->Fetch("CALL Select_ConfirmEmailExistance('abc#abc.com')");
// Assign your true/false
$containsResult = ($call1 !== 0)? 1:0;
// Run second query and return array or false (0)
if($containsResult == 0)
$data = $query->Fetch("CALL insert_Userinfo('abc','def','abc#abc.com','mnop')");
// Display returned result
print_r($data);
It is quite simple. Your code is fine but you only have to create two separete functions and simply call those functions instead of the code directly.
I am using a function in php for all select queries so that i can dynamically retrieve data from my database ..... I just wanted to know that is my code secure and efficient or if their is a better way to do this, if so please point me to the right direction...thanks
class mysql {
private $conn;
function __construct(){
$this->conn= new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME);
if( mysqli_connect_errno() )
{
trigger_error('Error connecting to host. '.$this->connections[$connection_id]->error, E_USER_ERROR);
}
}
function extracting_data($table, $fields,$condition,$order,$limit){
$query="SELECT ".$fields."
FROM ".$table."
WHERE id =".$this->sql_quote($condition)."
ORDER BY ".$order."
LIMIT ".$limit." ";
//echo $query;
if($stmt = $this->conn->prepare($query)) {
$stmt->execute();
$row = array_pad(array(), $stmt->field_count, '');
$params = array();
foreach($row as $k=>$v) {
$params[] = &$row[$k];
}
call_user_func_array(array($stmt,'bind_result'),$params);
$result = array();
while($stmt->fetch()) {
foreach ($row as $b=>$elem) {
$vals[$b]=$row[$b];
}
$result[]=$vals;
}
$stmt->close();
return $result;
}
}
function sql_quote( $value )
{
if( get_magic_quotes_gpc() )
{
$value = stripslashes( $value );
}
//check if this function exists
if( function_exists( "mysql_real_escape_string" ) )
{
$value = mysql_real_escape_string( $value );
}
//for PHP version < 4.3.0 use addslashes
else
{
$value = addslashes( $value );
}
return $value;
}
}
Now to call the function I am using ::>
$connection=New mysql();
$extract=$connection->extracting_data("tablename","id,name,points","$_GET['id']","date desc","0,10");
The function returns a multi-dimensional array in $result and stores it in $extract ,depending on the data I want to extract..
Any improvements or other suggestions would be appreciated ...
Instead of binding the results and having to do loads of looping, you could simply use mysqli::query() and mysqli_result::fetch_all().
if($stmt = $this->conn->query($query)) {
$result = $stmt->fetch_all(MYSQLI_ASSOC);
$stmt->close();
return $result;
}
You would be better off binding your input variables rather than building up an SQL string containing them, but that may not be feasible using your current approach.
Edit
Sorry, I was an idiot and didn't notice that fetch_all() is only in PHP >= 5.3. You can still do this though which is simpler:
if($stmt = $this->conn->query($query)) {
$result = array();
while ($row = $stmt->fetch_assoc()) {
$result[] = $row;
}
$stmt->close();
return $result;
}
You should watch where the parameters for your function come from. If they come from an unreliable source, then it's very insecure.
If someone passes something like 1 ; DROP TABLE tablename ; SELECT * FROM dual WHERE 1 in the $condition parameter, you'll get the Little Bobby Tables scenario.
Your query will look like the following:
SELECT id, name, points
FROM tablename
WHERE id
ORDER BY
DATE DESC
LIMIT 0, 10
The id here will be casted to BOOLEAN, and the query will select all ids except 0 and NULL.
Is it really what you want?
You probably want to change your $condition to 'id = $id' or something like that.
Do you really need this level of abstraction: generating queries from uknown tables with unknown fields but with predefined SELECT / FROM / ORDER BY / LIMIT stucture?