My php knowledge is fairly limited but I've recently needed to update a number of web pages from an older version of php 5.2 to php 7.3.
I've managed to update most of the mysql references to mysqli etc and get things working correctly, however there is one page that makes use of a calendar and I'm really struggling with this section and the fetch_field part in particular as any examples I have found don't seem to be in a similar format.
The code I need to update is below;
require_once('Connections/connAsh.php');
mysql_select_db($database_connAsh, $connAsh);
function selectonerow($fieldsarray, $table, $uniquefield, $uniquevalue)
{
//The required fields can be passed as an array with the field names or as a comma separated value string
if (is_array($fieldsarray)) {
$fields = implode(", ", $fieldsarray);
} else {
$fields = $fieldsarray;
}
//performs the query
$result = mysql_query("SELECT $fields FROM $table WHERE $uniquefield = '$uniquevalue'") or die("Could not perform select query - " . mysql_error());
$num_rows = mysql_num_rows($result);
//if query result is empty, returns NULL, otherwise, returns an array containing the selected fields and their values
if ($num_rows == NULL) {
return NULL;
} else {
$queryresult = array();
$num_fields = mysql_num_fields($result);
$i = 0;
while ($i < $num_fields) {
$currfield = mysql_fetch_field($result, $i);
$queryresult[$currfield->name] = mysql_result($result, 0, $currfield->name);
$i++;
}
return $queryresult;
}
}
My attempts at editing this are;
require_once('../Connections/connAsh.php')
$connAsh->select_db($database_connAsh);
function selectonerow($fieldsarray, $table, $uniquefield, $uniquevalue)
{
//The required fields can be passed as an array with the field names or as a comma separated value string
if (is_array($fieldsarray)) {
$fields = implode(", ", $fieldsarray);
} else {
$fields = $fieldsarray;
}
//performs the query
$result = $connAsh->query("SELECT $fields FROM $table WHERE $uniquefield = '$uniquevalue'") or die("Could not perform select query - " . mysqli_error());
$num_rows = mysqli_num_rows($result);
//if query result is empty, returns NULL, otherwise, returns an array containing the selected fields and their values
if ($num_rows == NULL) {
return NULL;
} else {
$queryresult = array();
$num_fields = mysqli_num_fields($result);
$i = 0;
while ($i < $num_fields) {
$currfield = mysqli_fetch_field($result);
$queryresult[$currfield->name] = mysqli_fetch_array($result, MYSQLI_BOTH);
$i++;
}
return $queryresult;
}
}
The original function is wrong on so many levels. And there is no point in recreating its functionality.
Basically all you are bargaining for here is just a few SQL keywords. But these keywords contribute for readability.
For some reason you decided to outsmart several generations of programmers who are pretty happy with SQL syntax, and make unreadable gibberish
$row = selectonerow("some, foo, bar", "baz", "id", [$uniquevalue]);
instead of almost natural English
$row = selectonerow("SELECT some, foo, bar FROM baz WHERE id=?", [$uniquevalue]);
Come on. It doesn't worth.
Make your function accept a regular SQL query, not a limited unintelligible mess.
function selectonerow(mysqli $conn, string $sql, array $params = []): array
{
if ($params) {
$stmt = $conn->prepare($sql);
$stmt = $mysqli->prepare($sql);
$stmt->bind_param(str_repeat("s", count($params), ...$params);
$stmt->execute();
$result = $stmt->get_result()
} else {
$result = $conn->query($sql);
}
return $result->fetch_assoc();
}
This function will let you to use any query. For example, need a row with max price?
$row = selectonerow("SELECT * FROM baz ORDER BY price DESC LIMIT 1");
Need a more complex condition? No problem
$sql = "SELECT * FROM baz WHERE email=? AND activated > ?";
$row = selectonerow($sql, [$email, $date]);
and so on. Any SQL. Any condition.
I would recommend to get rid of this function or replace it with a function suggested by YCS.
If you really want to continue using this function consider the following fixes. You made the code inside extremely complicated and you forgot to pass the connection variable into the function. I have simplified it:
// open the DB connection properly inside Connections/connAsh.php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$connAsh = new mysqli('host', 'user', 'pass', $database_connAsh);
$connAsh->set_charset('utf8mb4');
// your function:
function selectonerow(mysqli $connAsh, $fieldsarray, $table, $uniquefield, $uniquevalue): array
{
//The required fields can be passed as an array with the field names or as a comma separated value string
if (is_array($fieldsarray)) {
$fields = implode(", ", $fieldsarray);
} else {
$fields = $fieldsarray;
}
//performs the query
$stmt = $connAsh->prepare("SELECT $fields FROM $table WHERE $uniquefield = ?");
$stmt->bind_param('s', $uniquevalue);
$stmt->execute();
return $stmt->get_result()->fetch_assoc();
}
This is your function, but with a lot of noise removed. I added $connAsh in the function's signature, so you must pass it in every time you call this function. The function will always return an array; if no records are fetched the array will be empty. This is the recommended way. Also remember to always use prepared statements!
Related
I'm working on a project for uni and have been using the following code on a testing server to get all devices from a table based on a user_id:
public function getAllDevices($user_id) {
$stmt = $this->conn->prepare("SELECT * FROM devices WHERE primary_owner_id = ?");
$stmt->bind_param("i", $user_id);
$stmt->execute();
$devices = $stmt->get_result();
$stmt->close();
return $devices;
}
This worked fine on my testing server but returns this error when migrating over to the university project server:
Call to undefined method mysqli_stmt::get_result()
Some googling suggests using bind_result() instead of get_result() but I have no idea how to do this all fields in the table. Most examples only show returning one field
Any help would be much appreciated
Assuming you can't use get_result() and you want an array of devices, you could do:
public function getAllDevices($user_id) {
$stmt = $this->conn->prepare("SELECT device_id, device_name, device_info FROM devices WHERE primary_owner_id = ?");
$stmt->bind_param("i", $user_id);
$stmt->execute();
$stmt->bind_result($id, $name, $info);
$devices = array();
while($stmt->fetch()) {
$tmp = array();
$tmp["id"] = $id;
$tmp["name"] = $name;
$tmp["info"] = $info;
array_push($devices, $tmp);
}
$stmt->close();
return $devices;
}
This creates a temporary array and stores the data from each row in it, and then pushes it to the main array. As far as I'm aware, you can't use SELECT * in bind_result(). Instead, you will annoyingly have to type out all the fields you want after SELECT
By now, you've certainly grasped the idea of binding to multiple variables. However, do not believe the admonitions about not using "SELECT *" with bind_result(). You can keep your "SELECT *" statements... even on your server requiring you to use bind_result(), but it's a little complicated because you have to use PHP's call_user_func_array() as a way to pass an arbitrary (because of "SELECT *") number of parameters to bind_result(). Others before me have posted a handy function for doing this elsewhere in these forums. I include it here:
// Take a statement and bind its fields to an assoc array in PHP with the same fieldnames
function stmt_bind_assoc (&$stmt, &$bound_assoc) {
$metadata = $stmt->result_metadata();
$fields = array();
$bound_assoc = array();
$fields[] = $stmt;
while($field = $metadata->fetch_field()) {
$fields[] = &$bound_assoc[$field->name];
}
call_user_func_array("mysqli_stmt_bind_result", $fields);
}
Now, to use this, we do something like:
function fetch_my_data() {
$stmt = $conn->prepare("SELECT * FROM my_data_table");
$stmt->execute();
$result = array();
stmt_bind_assoc($stmt, $row);
while ($stmt->fetch()) {
$result[] = array_copy($row);
}
return $result;
}
Now, fetch_my_data() will return an array of associative-arrays... all set to encode to JSON or whatever.
It's kinda crafty what is going on, here. stmt_bind_assoc() constructs an empty associative array at the reference you pass to it ($bound_assoc). It uses result_metadata() and fetch_field() to get a list of the returned fields and (with that single statement in the while loop) creates an element in $bound_assoc with that fieldname and appends a reference to it in the $fields array. The $fields array is then passed to mysqli_stmt_bind_result. The really slick part is that no actual values have been passed into $bound_assoc, yet. All of the fetching of the data from the query happens in fetch_my_data(), as you can see from the fact that stmt_bind_assoc() is called before the while($stmt->fetch()).
There is one catch, however: Because the statement has bound to the references in $bound_assoc, they are going to change with every $stmt->fetch(). So, you need to make a deep copy of $row. If you don't, all of the rows in your $result array are going to contain the same thing: the last row returned in your SELECT. So, I'm using a little array_copy() function that I found with the Google:
function array_copy( array $array ) {
$result = array();
foreach( $array as $key => $val ) {
if( is_array( $val ) ) {
$result[$key] = arrayCopy( $val );
} elseif ( is_object( $val ) ) {
$result[$key] = clone $val;
} else {
$result[$key] = $val;
}
}
return $result;
}
Your question suggests that you have MySQL Native driver (MySQLnd) installed on your local server, but MySQLnd is missing on the school project server. Because get_result() requires MySQLnd.
Therefore, if you still want to use get_result() instead of bind_result() on the school project server, then you should install MySQLnd on the school project server.
in order to use bind_result() you can't use queries that SELECT *.
instead, you must select individual column names, then bind the results in the same order. here's an example:
$stmt = $mysqli->prepare("SELECT foo, bar, what, why FROM table_name WHERE id = ?");
$stmt->bind_param("i", $id);
if($stmt->execute()) {
$stmt->bind_result($foo, $bar, $what, $why);
if($stmt->fetch()) {
$stmt->close();
}else{
//error binding result(no rows??)
}
}else{
//error with query
}
get_result() is now only available in PHP by installing the MySQL native driver (mysqlnd). In some environments, it may not be possible or desirable to install mysqlnd.
Notwithstanding, you can still use mysqli to do 'select *' queries, and get the results with the field names - although it is slightly more complicated than using get_result(), and involves using php's call_user_func_array() function. See example below which does a simple 'select *' query, and outputs the results (with the column names) to an HTML table:
$maxaccountid=100;
$sql="select * from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('i', $maxaccountid);
$stmt->execute();
print "<table border=1>";
print "<thead><tr>";
$i=0;
$meta = $stmt->result_metadata();
$query_data=array();
while ($field = $meta->fetch_field()) {
print "<th>" . $field->name . "</th>";
$var = $i;
$$var = null;
$query_data[$var] = &$$var;
$i++;
}
print "</tr></thead>";
$r=0;
call_user_func_array(array($stmt,'bind_result'), $query_data);
while ($stmt->fetch()) {
print "<tr>";
for ($i=0; $i<count($query_data); $i++) {
print "<td>" . $query_data[$i] . "</td>";
}
print "</tr>";
$r++;
}
print "</table>";
$stmt->close();
print $r . " Records<BR>";
I have a custom html page which posts to php variables which then fills out custom sql queries.
function load_table($db, $old_table, $startRow, $nameColumn, $ipColumn, $addressColumn, $cityColumn, $stateColumn, $zipColumn, $countryColumn)
{
$select = "SELECT $nameColumn, $ipColumn, $addressColumn, $cityColumn, $stateColumn, $zipColumn, $countryColumn FROM " .$old_table.";";
$q = mysqli_query($db, $select);
return $q;
}
It works perfectly when all the variables are holding a value, but I need a way to dynamically assert this query, so that if the user is missing a column, i.e zip code is not in their table, it will still run without ruining the query.
$array = array();
if ($nameColumn)
$array[] = $nameColumn;
if ($ipColumn)
$array[] = $ipColumn;
// etc...
$cols = implode(',', $array);
if ($cols)
{
$select = "SELECT $cols FROM $old_table;";
$q = mysqli_query($db, $select);
return $q;
}
Or you can use
$select = "SELECT ".(($nameColumn != '')?$nameColumn.",":"")." .......";
See also: http://br2.php.net/manual/en/function.func-get-args.php
Put all your variables in an array then do the following:
function load_table($db, $old_table, $startRow, array $columns) {
$columns = array_filter($columns, 'strlen'); // removes empty values
$select = "SELECT " . implode(",", $columns) . " FROM " .$old_table.";";
$q = mysqli_query($db, $select);
return $q;
}
You can give it a default:
function load_table($db, $old_table, $startRow, $nameColumn="Default name", $ipColumn, $addressColumn, $cityColumn, $stateColumn, $zipColumn, $countryColumn)
In this case $nameColumn will always have a value unless otherwise specified
I have a PHP function that extract dat of an invoice from DB.
The invoice may have more then one line (one product).
function getInvoiceLines($id)
{
$res = mysql_query("select * from invoice_lines where id = $id ");
while ($row = mysql_fetch_array($res))
{
$res_retun['ref']=$row['ref'];
$res_retun['label']=$row['label'];
$res_retun['price']=$row['label'];
$res_retun['qty']=$row['qty'];
}
return $res_retun ;
}
I found this link Create a Multidimensional Array with PHP and MySQL and I made this code using that concept.
Now, how can I move something like a cursor to the next line and add more lines if there's more in MySQL result??
If it's possible, how can I do to show data in HTML with for ??
A little modification should get what you want, below the [] operator is a shorthand notation to add elements to an array, the problem with your code is that you are overwriting the same keys on each iteration
// fetch only what you need;
$res = mysql_query("select ref, label, price, qty from invoice_lines where id = $id ");
while ($row = mysql_fetch_array($res))
{
$res_return[] = $row;
}
return $res_return;
Note, I fixed some of your typos (you were using $rw instead of $row in the loop of your original code)
If you used PDO with fetchAll() you would be returned with the array your expecting, also be safe from nastys:
<?php //Cut down
$db = new PDO("mysql:host=localhost;dbname=dbName", 'root', 'pass');
$sql = "SELECT * FROM invoice_lines WHERE id = :id ";
$stmt = $db->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->execute();
$res_return = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
Then you just loop through the array like with any other array:
<?php
foreach($res_return as $row){
echo $row['ref'];
...
...
}
?>
Also id should not have more then 1 row it should be unique IF its your primary key.
If you were using PDO like you should be it would be super easy and you would solve your sql injection issues
$db = new PDO(...);
function getInvoiceLines( $db, $id )
{
$stmnt = $db->prepare("select ref, label, price, qty from invoice_lines where id=?");
$stmnt->execute( array( $id ) );
return $stmnt->fetchAll( PDO::FETCH_ASSOC );
}
Make variable global first Then access it in function. For exp.
$return_arr = array(); // outside function
$i = 0;
cal_recursive(); // call function first time
function cal_recursive(){
global $return_arr;
global $i;
$return_arr[$i] = // here push value to array variable
$i++;
// do code for recursive function
return $return_arr // after end
}
It must be Monday, the heat or me being stupid (prob the latter), but for the life of me I cannot get a simple php function to work.
I have a simple query
$sql = mysql_query("SELECT * FROM table WHERE field_name = '$input'");
Which I want to run through a function: say:
function functionname($input){
global $field1;
global $field2;
$sql = mysql_query("SELECT * FROM table WHERE field_name = '$input'");
while($row = mysql_fetch_array($sql)) :
$field1[] = $row['field1'];
$field2[] = $row['field2'];
endwhile;
mysql_free_result($sql);
}
So that I can call the function in numerious places with differeing "inputs". Then loop through the results with a foreach loop.
Works fine the first time the function is called, but always gives errors there after.
As said "It must be Monday, the heat or me being stupid (prob the latter)".
Suggestions please as I really only want 1 function to call rather than rewrite the query each and every time.
This is the error message
Fatal error: [] operator not supported for strings in C:\xampp\htdocs\functions.php on line 270
function functionname($input){
$sql = mysql_query("SELECT field1,field2 FROM table WHERE field_name = '$input'");
$result = array('field1' => array()
'field2' => array()
);
while($row = mysql_fetch_array($sql)) :
$result['field1'][] = $row['field1'];
$result['field2'][] = $row['field2'];
endwhile;
mysql_free_result($sql);
return $result;
}
it seems that somewhere the $field1 or $field2 are converted to strings and you cant apply the [] to a string...
i'd say that you have to do:
$field1 = array();
$field2 = array();
before the WHILE loop
The problem is that you so called arrays are strings!
global $field1;
global $field2;
var_dump($feild1,$feild2); //Will tell you that there strings
Read the error properly !
[] operator not supported for strings
And the only place your using the [] is withing the $feild - X values
GLOBAL must work because the error is telling you a data-type, i.e string so they must have been imported into scope.
another thing, why you selecting all columns when your only using 2 of them, change your query to so:
$sql = mysql_query("SELECT feild1,feild2 FROM table WHERE field_name = '$input'");
another thing is that your using mysql_fetch_array witch returns an integer indexed array, where as you want mysql_fetch_assoc to get the keys.
while($row = mysql_fetch_assoc($sql)) :
$field1[] = $row['field1'];
$field2[] = $row['field2'];
endwhile;
What I would do
function SomeFunction($variable,&$array_a,&$array_b)
{
$sql = mysql_query("SELECT field1,field2 FROM table WHERE field_name = '$variable'");
while($row = mysql_fetch_assoc($sql))
{
$array_a[] = $row['field1'];
$array_b[] = $row['field2'];
}
mysql_free_result($sql);
}
Then use like so.
$a = array();
$b = array();
SomeFunction('Hello World',&$a,&$b);
In my opinion, it's pretty unusual and even useless approach at all.
This function is too localized.
To make a general purpose function would be a way better.
<?
function dbgetarr(){
$a = array();
$query = array_shift($args);
foreach ($args as $key => $val) {
$args[$key] = "'".mysql_real_escape_string($val)."'";
}
$query = vsprintf($query, $args);
$res = mysql_query($query);
if (!$res) {
trigger_error("dbgetarr: ".mysql_error()." in ".$query);
return FALSE;
} else {
while($row = mysql_fetch_assoc($res)) $a[]=$row;
}
return $a;
}
and then call it like this
$data = dbgetarr("SELECT field1,field2 FROM table WHERE field_name = %s",$input);
foreach ($data as $row) {
echo $row['field1']." ".$row['field1']."<br>\n";
}
To understand your issue, we need the error, however, are you sure you are going about this in the right way?
Why do you need to call the function multiple times if you are just changing the value of the input field?
You could improve your SQL statement to return the complete result set that you need the first time.. i.e. SELECT * FROM table GROUP BY field_name;
Not sure if that approach works in your scenario, but in general you should aim to reduce the number of round trips to your database.
I don't know, i right or not. But i advise to try this:
function functionname($input){
global $field1;
global $field2;
$sql = mysql_query("SELECT * FROM `table` WHERE `field_name` = '" . $input . "'");
while($row = mysql_fetch_assoc($sql)) :
$field1[] = $row['field1'];
$field2[] = $row['field2'];
endwhile;
mysql_free_result($sql);
}
I want to make a simple function that I can call on to query my database. I pass the "where" part of the query to it and in the code below, my $q variable is correct. However, what should I then do to be able to use the data? I'm so confused at how to do something I'm sure is extremely easy. Any help is greatly appreciated!
function getListings($where_clause)
{
$q = "SELECT * FROM `listings` $where_clause";
$result = mysql_query($q,$dbh);
foreach (mysql_fetch_array($result) as $row) {
$listingdata[] = $row;
}
return $listingdata;
}
Your function should be like this:
function getListings($where_clause, $dbh)
{
$q = "SELECT * FROM `listings` $where_clause";
$result = mysql_query($q, $dbh);
$listingdata = array();
while($row = mysql_fetch_array($result))
$listingdata[] = $row;
return $listingdata;
}
Improvements over your function:
Adds MySQL link $dbh in function arguments. Passit, otherwise query will not work.
Use while loop instead of foreach. Read more here.
Initialize listingdata array so that when there is no rows returned, you still get an empty array instead of nothing.
Do you have a valid db connection? You'll need to create the connection (apparently named $dbh) within the function, pass it in as an argument, or load it into the function's scope as a global in order for $result = mysql_query($q,$dbh); to work.
You need to use while, not foreach, with mysql_fetch_array, or else only the first row will be fetched and you'll be iterating over the columns in that row.
$q = "SELECT * FROM `listings` $where_clause";
$result = mysql_query($q,$dbh);
while (($row = mysql_fetch_array($result)) != false)
{
$listingdata[] = $row;
}
Always add error handling in your code. That way you'll see what is going wrong.
$result = mysql_query($q,$dbh);
if (!$result) {
trigger_error('Invalid query: ' . mysql_error()." in ".$q);
}
Here is a function which will save you some time. First Argument tablename, then condition(where), fields and the order. A simple query will look like this : query_db('tablename');
function query_db($tbl_name,$condition = "`ID` > 0",$fields = "*",$order="`ID` DESC"){
$query="SELECT ".$fields." FROM `".$tbl_name."` WHERE ".$condition." ORDER BY".$order;
$query=$con->query($query);
$row_data=array();
while($rows = $query->fetch_array()){
$row_data[] = $rows;
}
return $row_data;
}