MySQL bind_param writes NULL to table - php

Problem: Even though my $settings array has values (int) in them, MySQL writes NULL into the table both when the value is 0 and 2.
For reference, each index in the $settings array is an array of [0] = max and [1] = min.
public function updateAdaptiveArmour($gameid, $shipid, $settings){
foreach ($settings as $key => $value){
debug::log($key." ".$value[0]." ".$value[1]);
//just to show the contents
// [561103190304f][2015-10-04 12:44:41] particle 4 2
// [56110319035b3][2015-10-04 12:44:41] laser 0 0
// [56110319035b3][2015-10-04 12:44:41] molecular 0 0
}
try {
if ($stmt = $this->connection->prepare(
"UPDATE
tac_adaptivearmour
SET
particlealloc = ?,
laseralloc = ?,
molecularalloc = ?
WHERE
gameid = ?
AND shipid = ?
"
))
{
$stmt->bind_param('iiiii', $settings[0][1], $settings[1][1], $settings[2][1], $gameid, $shipid);
$stmt->execute();
$stmt->close();
}
}
catch(Exception $e) {
throw $e;
}
}
Ideally, for this example, I would want to UPDATE to 2 / 0 / 0 instead of null / null / null.

Your array is populated as follows:
$settings = [
'particle' => [4, 2],
'laser' => [0, 0],
'molecular' => [0, 0]
];
I hope that answers the question without needing to further explain it.
It will be fixed as follows:
$stmt->bind_param('iiiii',
$settings['particle'][1],
$settings['laser'][1],
$settings['molecular'][1],
$gameid,
$shipid
);

Related

Filtering ARRAY and grabbing distinct entry

Currently I am collecting a count of desktop and mobile devices... the count is coming back correctly based in the items total in the ARRAY. But, now I need to remove duplicates... Example user_id = 001 can have 10 entries for IOS ... so I would need to do something like ... IF $row['last_login'] Date() is the most current then grab that entry and count as 1. End result for user_id = 001 would be 1 entry count and not 10 (which I am getting now).
if ($results = $dbh->runQuery($sql)) {
foreach ($results as $key=>$row){
$users[$row['user_id']][] = array('user_id'=>$row['user_id'],
'racid' => $row['racid'],
'email' => $row['email'],
'last_login' => $row['last_login'],
'fname' => $row['fname'],
'lname' => $row['lname'],
'role_id' => $row['role_id'],
'role_name' => $row['role_name'],
'ios_device_token' => $row['ios'],
'roid_device_token' => $row['roid'],
'p_name' => $row['p_name']);
if($row['ios'] !== null && $row['ios'] !== '' && $row['ios'] !== '-1'){
$ios_count++;
}
if($row['android'] !== null && $row['android'] !== '' && $row['android'] !== '-1'){
$android_count++;
}
$invalidValues = [null, "", -1];
if(in_array($row['ios'], $invalidValues) && in_array($row['android'], $invalidValues)){
$desktop_count++;
}
}
}
Using associative arrays, you can "distinctify" by your own criterium. Something like the following code.
However what #esqew said (commenting your question) about altering the SQL instead of the PHP is probably a cleaner angle, especially since PHP is generally quite slow.
if ($results = $dbh->runQuery($sql)) { // that exists already
$latestEntries = []; // assoc. array: key=user, value=row
foreach ($results as $row) { // that exists already
// assuming 'last_login' is a timestamp or any format that can be used in inequality
// otherwise cook your own comparison function
if (
!$latestEntries[$row['user_id']]
|| $latestEntries[$row['user_id']]['last_login'] < $row['user_id']['last_login']
) {
$latestEntries[$row['user_id']] = $row;
}
// rest of your code that exists already
}
// here, after the loop, $latestEntries has the latest entry for each user found in $results
}

PHP PDO bind param [duplicate]

I have function in PHP, which should bind in MySQL IN statement so many variables, that is in array.
My problem is that variable and key is changing but function bind only last value n times.
I don't have idea where is the problem...
Here is my class method:
public function getOtListByOtNumbers($conditions){
$data_array = $conditions[SEARCH_OT];
# To find last key (remove coma)
$quantity = count($data_array);
$marks = '';
# Bind name string && rewriting value as integer
foreach ($data_array as $key => $value){
$i = $key+1;
if ($i == $quantity){
$marks .= ':key'.$i;
}
else {
$marks .= ':key'.$i.', ';
}
}
# Query
$sql="
SELECT
c_int_id,
c_ot,
c_tickets_amount,
c_basket_value,
c_person,
c_company,
c_city,
c_package_number,
c_delivery_method,
c_ot_date,
c_email,
c_phone,
c_comment,
c_send
FROM ws_orders
WHERE c_ot IN (".$marks.")
ORDER BY c_int_id DESC
LIMIT :first, :last ";
$stmt = $this->PDO->prepare($sql);
# Bind n values
// Here is a problem
var_dump($data_array); // var dump 1
foreach ($data_array as $key => $param){
$key_number = $key +1;
$key_name = 'key'.$key_number;
$stmt->bindParam($key_name, $param, PDO::PARAM_INT);
var_dump($key_name); // var dump 2
var_dump($param); // var dump 3
}
# Bind limit values
$stmt->bindParam('first', $conditions[OT_SEARCH_FIRST_ROW], PDO::PARAM_INT);
$stmt->bindParam('last', $conditions[OT_SEARCH_ROW_LIMIT], PDO::PARAM_INT);
# If executed return result
if ($stmt->execute() != FALSE) {
$stmt_result = $stmt->fetchAll();
$stmt->closeCursor();
var_dump($stmt_result); // var dump 4
# If not executed print debug and return FALSE
} else {
var_dump($stmt->errorInfo());
$this->debugQuery($stmt);
$stmt_result = FALSE;
}
return $stmt_result;
}
Here are var dupms:
var dump 1
array (size=2)
0 => string '2761531'
1 => string '2760650'
var dump 2 & 3
string 'key1' (length=4)
string '2761531'
string 'key2' (length=4)
string '2760650'
SQL query from this execution
SELECT
c_int_id,
c_ot,
c_tickets_amount,
c_basket_value,
c_person,
c_company,
c_city,
c_package_number,
c_delivery_method,
c_ot_date,
c_email,
c_phone,
c_comment,
c_send
FROM ws_orders
WHERE c_ot IN ('2760650', '2760650')
ORDER BY c_int_id DESC
LIMIT 0, 30
So what I am doing wrong?
EDIT
So i did it ;)
The problem was with foreach
Instead of:
foreach ($data_array as $key => $param){
$key_number = $key +1;
$key_name = 'key'.$key_number;
$stmt->bindParam($key_name, $param, PDO::PARAM_INT);
var_dump($key_name); // var dump 2
var_dump($param); // var dump 3
}
I give:
for ($key_number = 0; $key_number < $quantity + 1; $key_number++) {
$key_name = 'key'.$key_number;
$stmt->bindParam($key_name, $data_array[$key_number], PDO::PARAM_INT);
}
And it works, but i still don't know what the problem was with earlier foreach...
There is the difference between PDO::bindParam() and PDO::bindValue(). PDO::bindParam binds reference, not value. When foreach process ends, $param will reference to the last array value. In the time of execute call all binded references will be evaluated to same value.
Official PDO::bindParam documentation says:
Unlike PDOStatement::bindValue(), the variable is bound as a reference
and will only be evaluated at the time that PDOStatement::execute() is
called.
If you want bind values in foreach use PDO::bindValue.
If you pass the variable as reference it would work fine for value, but won't work for key.
Example:
foreach ($data_array as $key => &$param) {
$key_number = $key + 1; //this won't work
$key_name = 'key' . $key_number;
$stmt->bindParam($key_name, $param, PDO::PARAM_INT);
var_dump($key_name); // var dump 2
var_dump($param); // var dump 3
}
The problem is that BindParam Passes the second value by reference. PHP reuses (or appears to in this case) the address of the $param, and not the actual value.
Your foreach could have used:
$stmt->bindParam($key, $data_array[$key]);
This has the effect of binding the address location of the array at that key location, so when your sql executes, it gets the right value.
You probably wanted:
$stmt->bindValue($key, $param);
which should evaluate in the foreach loop instead of at the execute statement, and is a passed value instead of an address location.

Summing the values of two arrays in php

There is a problem:
After submitting a form I receive the indexed array as a SQL-query result and the goal is to sum each next array values with the values of previously received arrays and put the sums into result array
Example:
// 1st query result
$product_amount = [0 => 0.36,
1 => 0.14,
2 => 0.42]
// 2nd query result
$product_amount = [0 => 0.28,
1 => 0.12,
2 => 0.40]
// n-th query result
$product_amount = [0 => 0.16,
1 => 0.14,
2 => 0.42]
// the sum
$total = [0 => 0.80,
1 => 0.40,
2 => 1.24]
How to do it?
The code that creates an array:
function doseCount($num){
return ($num/100) * intval($_POST['portion']); //getting multiplier for productAmount() function
}
function productAmount(){
global $link; //connection to the MySQL server
if(isset($_POST['product'])){
$product_amount_query = 'SELECT va.vitamin_a, va.vitamin_b1, va.vitamin_b2, va.vitamin_b3, va.vitamin_b5,
va.vitamin_b6, va.vitamin_bc_b9, va.vitamin_b12, va.vitamin_c, va.vitamin_d, va.vitamin_e, va.biotin, va.vitamin_k,
va.flavonoids, va.lipoic_acid FROM products_list p, vitamins_amount va WHERE p.id = va.product_id AND p.name = ?';
$product_amount_stmt = mysqli_prepare($link, $product_amount_query);
mysqli_stmt_bind_param($product_amount_stmt, "s", $_POST['product']);
mysqli_stmt_execute($product_amount_stmt);
$result = mysqli_stmt_get_result($product_amount_stmt);
$product = mysqli_fetch_array($result, MYSQLI_NUM);
return $product_final_result = array_map('doseCount', $product);
mysqli_stmt_close($product_amount_stmt);
mysqli_close($link);
}
}
$product_amount = productAmount();
After submit $product_amount array gets new data and this new value must be summed with previous.
You could accomplish this by combining array_map and array_sum. If you're using PHP 5.6 or greater, which you should, you could write something like this:
$total = array_map(function (...$vals) {
return array_sum($vals);
}, ...$results);
Assuming that $results contains all of your $product_amount arrays.
If you want to build $total incrementally instead of passing all query results at once, you can do this:
// Initialize $total array
$total = [0, 0, 0];
// Update $total for each query
$total = array_map(function (...$vals) {
return array_sum($vals);
}, $total, $product_amount);
This problem can be solved with proper use of sessions:
if (empty($_SESSION['product_amount'])){
$_SESSION['product_amount'] = $product_amount;
}else{
foreach ($_SESSION['product_amount'] as $key => $value) {
$_SESSION['product_amount'][$key] += $product_amount[$key];
}
}
Special thanks to Mawia HL for his help.

PDO binds n times same value with foreach

I have function in PHP, which should bind in MySQL IN statement so many variables, that is in array.
My problem is that variable and key is changing but function bind only last value n times.
I don't have idea where is the problem...
Here is my class method:
public function getOtListByOtNumbers($conditions){
$data_array = $conditions[SEARCH_OT];
# To find last key (remove coma)
$quantity = count($data_array);
$marks = '';
# Bind name string && rewriting value as integer
foreach ($data_array as $key => $value){
$i = $key+1;
if ($i == $quantity){
$marks .= ':key'.$i;
}
else {
$marks .= ':key'.$i.', ';
}
}
# Query
$sql="
SELECT
c_int_id,
c_ot,
c_tickets_amount,
c_basket_value,
c_person,
c_company,
c_city,
c_package_number,
c_delivery_method,
c_ot_date,
c_email,
c_phone,
c_comment,
c_send
FROM ws_orders
WHERE c_ot IN (".$marks.")
ORDER BY c_int_id DESC
LIMIT :first, :last ";
$stmt = $this->PDO->prepare($sql);
# Bind n values
// Here is a problem
var_dump($data_array); // var dump 1
foreach ($data_array as $key => $param){
$key_number = $key +1;
$key_name = 'key'.$key_number;
$stmt->bindParam($key_name, $param, PDO::PARAM_INT);
var_dump($key_name); // var dump 2
var_dump($param); // var dump 3
}
# Bind limit values
$stmt->bindParam('first', $conditions[OT_SEARCH_FIRST_ROW], PDO::PARAM_INT);
$stmt->bindParam('last', $conditions[OT_SEARCH_ROW_LIMIT], PDO::PARAM_INT);
# If executed return result
if ($stmt->execute() != FALSE) {
$stmt_result = $stmt->fetchAll();
$stmt->closeCursor();
var_dump($stmt_result); // var dump 4
# If not executed print debug and return FALSE
} else {
var_dump($stmt->errorInfo());
$this->debugQuery($stmt);
$stmt_result = FALSE;
}
return $stmt_result;
}
Here are var dupms:
var dump 1
array (size=2)
0 => string '2761531'
1 => string '2760650'
var dump 2 & 3
string 'key1' (length=4)
string '2761531'
string 'key2' (length=4)
string '2760650'
SQL query from this execution
SELECT
c_int_id,
c_ot,
c_tickets_amount,
c_basket_value,
c_person,
c_company,
c_city,
c_package_number,
c_delivery_method,
c_ot_date,
c_email,
c_phone,
c_comment,
c_send
FROM ws_orders
WHERE c_ot IN ('2760650', '2760650')
ORDER BY c_int_id DESC
LIMIT 0, 30
So what I am doing wrong?
EDIT
So i did it ;)
The problem was with foreach
Instead of:
foreach ($data_array as $key => $param){
$key_number = $key +1;
$key_name = 'key'.$key_number;
$stmt->bindParam($key_name, $param, PDO::PARAM_INT);
var_dump($key_name); // var dump 2
var_dump($param); // var dump 3
}
I give:
for ($key_number = 0; $key_number < $quantity + 1; $key_number++) {
$key_name = 'key'.$key_number;
$stmt->bindParam($key_name, $data_array[$key_number], PDO::PARAM_INT);
}
And it works, but i still don't know what the problem was with earlier foreach...
There is the difference between PDO::bindParam() and PDO::bindValue(). PDO::bindParam binds reference, not value. When foreach process ends, $param will reference to the last array value. In the time of execute call all binded references will be evaluated to same value.
Official PDO::bindParam documentation says:
Unlike PDOStatement::bindValue(), the variable is bound as a reference
and will only be evaluated at the time that PDOStatement::execute() is
called.
If you want bind values in foreach use PDO::bindValue.
If you pass the variable as reference it would work fine for value, but won't work for key.
Example:
foreach ($data_array as $key => &$param) {
$key_number = $key + 1; //this won't work
$key_name = 'key' . $key_number;
$stmt->bindParam($key_name, $param, PDO::PARAM_INT);
var_dump($key_name); // var dump 2
var_dump($param); // var dump 3
}
The problem is that BindParam Passes the second value by reference. PHP reuses (or appears to in this case) the address of the $param, and not the actual value.
Your foreach could have used:
$stmt->bindParam($key, $data_array[$key]);
This has the effect of binding the address location of the array at that key location, so when your sql executes, it gets the right value.
You probably wanted:
$stmt->bindValue($key, $param);
which should evaluate in the foreach loop instead of at the execute statement, and is a passed value instead of an address location.

Problem with 2 simultaneous connection with PDO/Mysql

Here is my simplified code:
$connexion = new PDO(SQL_DSN,SQL_USERNAME,SQL_PASSWORD);
$connexion2 = new PDO(SQL_DSN2,SQL_USERNAME2,SQL_PASSWORD2);
[...]
$sqlIndex = "SELECT index_key,index_platforms_code
FROM index
WHERE index_missions_id = :mission";
$initFiches = $connexion->prepare($sqlIndex);
$initFiches->bindParam(":mission" , $_GET['mission']);
$initFiches->execute();
try
{
while ($fiche = $initFiches->fetch(PDO::FETCH_ASSOC))
{
print_r($fiche);
foreach ($structure['champs'] as $masterChamp)
{
//$stmt = $connexion2->prepare($masterChamp['sql']);
}
}
}
catch (exception $e)
{
echo "error".$e->getMessage();
}
My output:
Array
(
[index_key] => 1
[index_platforms_code] => 1
)
Array
(
[index_key] => 2
[index_platforms_code] => 2
)
Array
(
[index_key] => 3
[index_platforms_code] => 3
)
Array
(
[index_key] => 4
[index_platforms_code] => 4
)
All Right, but if I uncomment this line
$stmt = $connexion2->prepare($masterChamp['sql']);
in the foreach, this line broke the while above and here is the new output:
Array
(
[index_key] => 1
[index_platforms_code] => 1
)
Someone have an idea?
Here's a solution that doesn't involve 2 connections and that's more optimized.
$connexion = new PDO(SQL_DSN,SQL_USERNAME,SQL_PASSWORD);
$sqlIndex = "SELECT index_key,index_platforms_code
FROM index
WHERE index_missions_id = :mission";
$initFiches = $connexion->prepare($sqlIndex);
$initFiches->bindParam(":mission" , $_GET['mission'], PDO::PARAM_STR);
$initFiches->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = $connexion->prepare("SELECT ...."); // Prepare outside of the loop, you don't have to prepare it X times, once is enough.
if(sizeof($data))
{
foreach($data as $row)
{
// Do your statement binding / executing.
}
}
Alternatively, it seems you might be able to do this with table joining rather than issuing a query for each row you get from the 1st table. Since you haven't posted the structure, I guess there's no much helping it at the moment.

Categories