trying to make my website a bit tidier and simpler to maintain so am trying to move alot of repeated code into functions.
I have a function that takes an argument for an ID, runs a database check using this ID in the where claus and then sets a new variable for the rowCount returned.
However it keeps returning 0 / nothing.
I have made a simple example of what im doing:
$buildID = 5;
function select_All_Comments_From_ID($buildID){
$idNew = $buildID;
global $idNew
}
select_All_Comments_From_ID($buildID);
echo $idNew;
Any idea why this is happening?
Here is what it actually looks like:
function select_All_Comments_From_ID($buildID){
$query = " SELECT * FROM comments WHERE buildID = :buildID";
$query_params = array(':buildID' => $buildID);
try {
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
$row = $stmt->fetch();
$countComments = $stmt->rowCount();
global $countComments;
}
catch(PDOException $ex) { die();
}
}
I then am trying to use
$countComments
But no luck.
The code itself works when not in the function.
global $idNew affects the variable lookup just when it's executed - not before. E.g. take a look at
<?php
$a = 9;
foo();
function foo() {
$a = 5; // this sets the value for the variable in the local lookup table
echo $a, "\r\n"; // scope of $a is still local -> 5
global $a; // now the lookup for "a" is switched to the global scope
echo $a, "\r\n"; // $a "points" to the global value -> 9
}
the output is
5
9
and in your case
function select_All_Comments_From_ID($buildID){
$idNew = $buildID;
global $idNew
}
the function writes the value to its local $idNew and then the lookup for idNew is switched to the global scope - but that doesn't copy the local value to the global scope; just the lookup has been changed.
Anyway as pointed out before you really should return the values instead of setting them globally. And if all you're interested in is the number of (matching) records in a table - not the payload data of the records - use a SELECT Count(...) query. Otherwise your script transfers all the data from the database server into the memory space of your php instance ...for nothing but heating up the cpu and memory.
function select_All_Comments_From_ID($buildID){
$query = " SELECT Count(*) as c FROM comments WHERE buildID = :buildID";
$query_params = array(':buildID' => $buildID);
try {
// what's $db here ?
// neither has it been passed to the function nor is it fetched from the global scope
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
$row = $stmt->fetch();
return $row['c'];
}
catch(PDOException $ex) {
// using die(...) is crude, even more so without any notice/text
die();
}
}
You have to define $countComments at outside of the function even if it defined as a global at inside of function.
Example :
<?php
$a = 1;
$b = 2;
function Sum()
{
global $a, $b;
$b = $a + $b;
}
Sum();
echo $b;
?>
You can return a value from your function, instead of using a Global, like this:
function select_All_Comments_From_ID($buildID){
$query = " SELECT * FROM comments WHERE buildID = :buildID";
$query_params = array(':buildID' => $buildID);
try {
$stmt = $db->prepare($query);
$stmt->execute($query_params);
$row = $stmt->fetch();
$countComments = $stmt->rowCount();
return $countComments; //sends the value back outside the scope of the function
}
catch(PDOException $ex) { die(); }
}
When you call the function, you need a variable to catch the return value, like this:
$buildID = 5;
$countComments = select_All_Comments_From_ID($buildID);
echo $countComments;
change
$countComments = $stmt->rowCount();
global $countComments;
in
$GLOBALS['countComments'] = $stmt->rowCount();
By the way, the comment is right, that's an awful solution, you should really change it.
Related
I need to write a PHP function to echo out MySQL rows as I give it the SQL query I want to be executed as the function argument. I have tried out the following code but it is giving me an undefined index error
function runQuery($query) {
$conn = mysqli_connect('localhost', 'root', '', 'mydb');
$result = mysqli_query($conn,$query);
while($row=mysqli_fetch_assoc($result)) {
$resultset[] = $row;
}
if(!empty($resultset))
return $resultset;
the code I am using to call the function is;
runQuery(SELECT * FROM mytable WHERE id='5')
echo $resultset['name'];
this, however, gives me this error, undefined index 'resultset' on line 25. any kind assistance would be appreciated
You dont have a $resultset in the scope of where you call the function. The function creates one, but that is only visible inside the function.
You will also have to put QUOTES around the query, you are passing a string there so it needs to be quoted.
Your errors should have generated quite a few error messages, if you were not getting them I have added 4 lines of code you should add while testing code for example if you are testing on a LIVE server with error reporting turned off.
You should also change the function to ensure you always return something
So amend the call to
ini_set('display_errors', 1);
ini_set('log_errors',1);
error_reporting(E_ALL);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
function runQuery($conn, $query) {
$resultset = [];
$result = mysqli_query($conn,$query);
while($row=mysqli_fetch_assoc($result)) {
$resultset[] = $row;
}
return $resultset;
}
$resultset = runQuery($conn, "SELECT * FROM mytable WHERE id='5'");
// as result will now be a multidimentional array
// you will need to loop over that to get each returned row
foreach ( $resultset as $row ) {
echo $row['name'];
}
AFTER your edit there is another error
$conn is not created inside the function, so will be invisible in the function code unless passed as a parameter to the function (there is another way but lets not get into the bad habit of using global variables)
First, your code is probably vulnerable to SQL Injection. Please take care of that, by using prepared statements for instance.
https://www.w3schools.com/sql/sql_injection.asp
https://websitebeaver.com/prepared-statements-in-php-mysqli-to-prevent-sql-injection
Other than that, you do not assign the return value of your function to a variable. You cannot use the $resultset defined in the function scope outside the function, as it is a different scope. Try the following:
$resultset = runQuery("SELECT * FROM mytable WHERE id='5'")
echo $resultset['name'];
I built a similar function recently - here is my code
function returnSQL($conn, $nameSql) {
$result = mysqli_query($conn, $nameSql);
if (!$result) {
return 0;
}
while ($res = mysqli_fetch_assoc($result)) {
$data[] = $res;
}
return $data;
}
The connection is setup outside the function and passed in as an argument along with the sql like this...
$conn = mysqli_connect($servername, $username, $password, $DBName);
if (!$conn) {
echo 'Failed to connect to database :- ' . $DBName . '<br>';
die();
}
$sql = "SELECT * FROM table";
$data = returnSQL($conn, $sql);
I'm no expert, but this works for me :)
What I notice from your code is that you are trying to access $resultset outside of the function it is declared in and I think it is not available as a global variable - perhaps it should be something like:
$returnValue = runQuery(SQL statement);
// $returnValue is assigned the array returned from runQuery()
echo $returnValue['name'];
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 have a function which retrieves user information and stores it in variables like so within a class:
public function UserInformation() {
$query = "SELECT * FROM users WHERE username = '$this->user'";
try {
$stmt = $this->db->prepare($query);
$stmt->execute();
}
catch(PDOException $ex)
{
die("Failed to run query: " . $ex->getMessage());
}
$rows = $stmt->fetch();
$email = $rows['email'];
$username = $rows['username'];
}
How would I then display a single variable from that function? I've tried echo $retrieveInfo->UserInformation->username; with no success, how would I do this?
You have defined local variables, that to be lost as soon as function ends its execution.
The more correct way of doing what you want would be to return the data from the function like:
$rows = $stmt->fetch();
return $rows;
And call the method like
$rows = $yourObject->UserInformation();
Or, if the object represents a particular user you could store the data retrieved in an instance members like:
$this->email = $rows['email'];
and then access them
$yourObject->email
This would work as well while the former is what I would prefer (I don't know the whole task though)
Okay, I've never ever used dynamic functions, not sure why, I've never liked using explode(), implode(), etc.
but I've tried it out, and something went wrong.
public function fetch($table, array $criteria = null)
{
// The query base
$query = "SELECT * FROM $table";
// Start checking
if ($criteria) {
$query .= ' WHERE ' . implode(' AND ', array_map(function($column) {
return "$column = ?";
}, array_keys($criteria)));
}
$check = $this->pdo->prepare($query) or die('An error has occurred with the following message:' . $query);
$check->execute(array_values($criteria));
$fetch = $check->fetch(PDO::FETCH_ASSOC);
return $fetch;
}
This is my query.
Basically I will return the variable $fetch which holds the fetch method.
and then somewhere, where I want to use the while loop to fetch data, I will use that:
$r = new Database();
while ($row = $r->fetch("argonite_servers", array("server_map" => "Wilderness")))
{
echo $row['server_map'];
}
Now, I am not getting any errors, but the browser is loading and loading forever, and eventually will get stuck due to lack of memory.
That's because the loop is running and running without stopping.
Why is it doing this? How can I get this dynamic query to work?
EDIT:
$r = new Database();
$q = $r->fetch("argonite_servers", array("server_map" => "Wilderness"));
while ($row = $q->fetch(PDO::FETCH_ASSOC))
{
echo $row['server_map'];
}
One nice feature of PDO is that the PDOStatement implements the Traversable. This means you can iterate it directly:
// `$check` is a `PDOStatement` object
$check = $this->pdo->prepare($query) or die('An error has occurred with the following message:' . $query);
$check->execute(array_values($criteria));
$check->setFetchMode(PDO::FETCH_ASSOC);
return $check;
Use it:
$statement = $r->fetch("argonite_servers", array("server_map" => "Wilderness"));
foreach ($statement as $row) {
}
this is because you call your fetch function in a loop and it re-starts the query every time. You need to call the $check->fetch() in loop instead.
or in other words, if your fetch function (which should probably have a different name) would return $check, then on the returned object you should call fetch() in a loop:
$r = new Database();
$q = $r->fetch(...);
while($q->fetch()){...}
you also need to edit your fetch function to end like this:
$check->execute(array_values($criteria));
return $check;
}
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 />;
}