I have some user uploaded images that can be sorted and need to save the image position. Was thinking that I could do this easy enough by just using the loop index while iterating through them. However using my $i variable to bind the 3rd param is being passed as a reference and I need the value. How do I get around this?
Here's the code:
$postId = $args['postId'];
$images = explode(",", $args['images']);
$sql = 'INSERT INTO post_image (name,postId,ordinal) VALUES ';
$part = array_fill(0, count($images), "(?, ?, ?)");
$sql .= implode(",", $part);
logit($sql);
try{
$db = DB::getInstance();
$stmt = $db->dbh->prepare($sql);
$count = count($images);
$n = 1;
for($i = 0; $i < $count; $i++){
$stmt->bindParam($n++, $images[$i]);
$stmt->bindParam($n++, $postId);
$stmt->bindParam($n++, $i);
}
$result = $stmt->execute();
if($result !== false) {
return true;
}else {
logit('Query Failed');
return false;
}
}catch(PDOException $e) {
logit($e->getMessage());
return false;
}
I fixed it by using bindValue for the third param.
Related
I'm writing some PHP to accept an array of numbers and names in POST and insert them into a MySQL table (named Contacts_table) Here's the version that works fine without any error:
<?php
// Includes
require_once 'Admin/Connector.php';
// Test if payload exists
if($_POST){
// Read payload into arrays
$ar = 0;
foreach($_POST as $entry){
$namenum = explode(',', $entry);
$names[$ar] = $namenum[1];
$numbers[$ar] = $namenum[0];
$ar += 1;
}
$namenum = NULL;
// Build SQL query
$sql = 'INSERT INTO Contact_table (NAME, PHONE) VALUES ';
$insertQuery = array();
$insertData = array();
$n = 0;
foreach ($numbers as $num) {
$insertQuery[] = '(?, ?)';
$insertData[] = $names[$n];
$insertData[] = $num;
$n++;
}
$sql .= implode(', ', $insertQuery);
$sql .= ' ON DUPLICATE KEY UPDATE name = COALESCE(VALUES(name), name);';
$n = NULL;
$num = NULL;
// Connect to MySQL database
$connect = dbconn(PROJHOST,PROJDB,PROJDBUSER,PROJDBPWD);
// Execute SQL query
$query = $connect->prepare($sql);
$query->execute($insertData);
$insertQuery = NULL;
$insertData = NULL;
$sql = NULL;
$query = NULL;
// Close connection to MySQL database
$connect = NULL;
}
?>
However, as you can see, I'm not using the bindParam() function here and just feeding the values directly to the execute() function. Many have recommended that I use bindParam() instead for server performance gains. Is it true or I am better off with this program as it stands? I did try writing and running a version of the above code using bindParam:
<?php
// Includes
require_once 'Admin/Connector.php';
// Test if payload exists
if($_POST){
// Read payload into arrays
$ar = 0;
foreach($_POST as $entry){
$namenum = explode(',', $entry);
$names[$ar] = $namenum[1];
$numbers[$ar] = $namenum[0];
$ar += 1;
}
$namenum = NULL;
// Build SQL query
$sql = 'INSERT INTO Contact_table (NAME, PHONE) VALUES ';
$insertQuery = array();
$insertData = array();
$n = 0;
foreach ($numbers as $num) {
$insertQuery[] = '(?, ?)';
$insertData[] = $names[$n];
$insertData[] = $num;
$n++;
}
$sql .= implode(', ', $insertQuery);
$sql .= ' ON DUPLICATE KEY UPDATE name = COALESCE(VALUES(name), name);';
$n = NULL;
$num = NULL;
// Connect to MySQL database
$connect = dbconn(PROJHOST,PROJDB,PROJDBUSER,PROJDBPWD);
// Prepare SQL query
$query = $connect->prepare($sql);
// Bind variables
foreach($insertData as $key => &$ins) {
$connect->bindParam($key+1,$ins);
}
// Execute SQL query
$query->execute();
$insertQuery = NULL;
$insertData = NULL;
$sql = NULL;
$query = NULL;
$key = NULL;
$ins = NULL;
// Close connection to MySQL database
$connect = NULL;
}
?>
But this code refuses to run and returns a fatal error – Call to undefined method PDO::bindParam(). What am I doing wrong here? I understand it's possible to write a much simpler code if I include execute() within the loop but that would spawn multiple queries which I want to avoid at all costs. My goal is a single query no matter what.
You can't $connect->bindParam($key+1,$ins);. Because PDO object doesn't have such method. Only PDOStatement has. That is why you've got error message.
You should :
$query->bindValue($key+1,$ins);
And you should use bindValue because if not, all your inserted values will get same value (the last one of $ins before you call execute).
I am getting Fatal error: Cannot pass parameter 3 by reference in line# 4
please suggest me solution I want the binding part dynamic.
$values = array($username,$password);
$query = "select * from users where email_id = ? and password = ?"
$this->con = new mysqli('localhost', 'username', 'password','dbname');
$stmt = $this->con->prepare($query);
$count = 0;
for ($i = 0; $i < count($values); $i++) {
$stmt->bind_param(++$count,$values[$i], PDO::PARAM_STR,12);
}
if ($stmt->execute()) {
while ($row = $this->stmt->fetch()) {
$data[] = $row;
}
return $data;
} else {
return null;
}
use bindValue()
$stmt->bindValue(++$count,$values[$i], PDO::PARAM_STR,12);
Ok, I thought I had this, but I can't see why it's not working...
I have a SELECT with a variable table, hence my columns (bind_result) is going to be variable.
I need to adjust for any number of columns coming back, and fetch as an associated array, since there will be multiple rows coming back:
// Get table data
$mysqli = new mysqli('host','login','passwd','db');
if ($mysqli->connect_errno()) { $errors .= "<br>Cannot connect: ".$mysqli->connect_error()); }
$stmt = $mysqli->prepare("SELECT * FROM ?");
$stmt->bind_param('s', $table);
$stmt->execute();
// Get bind result columns
$fields = array();
// Loop through columns, build bind results
for ($i=0; $i < count($columns); $i++) {
$fields[$i] = ${'col'.$i};
}
// Bind Results
call_user_func_array(array($stmt,'bind_result'),$fields);
// Fetch Results
$i = 0;
while ($stmt->fetch()) {
$results[$i] = array();
foreach($fields as $k => $v)
$results[$i][$k] = $v;
$i++;
}
// close statement
$stmt->close();
Any thoughts are greatly appreciated ^_^
EDIT: New code:
$mysqli = new mysqli('host','login','passwd','db');
if ($mysqli->connect_errno)) { $errors .= "<br>Cannot connect: ".$mysqli->connect_error()); }
$stmt = "SELECT * FROM ".$table;
if ($query = $mysqli->query($stmt)) {
$results = array();
while ($result = $query->fetch_assoc()) {
$results[] = $result;
}
$query->free();
}
$mysqli->close();
You can not bind the table name. Bind_param accept the column name and its datatype.
To use the table name dynamically use the below code:
$stmt = $mysqli->prepare("SELECT * FROM ".$table);
This function takes an array of integers
$this->grades
this array varies in size depending on what the user inputs.
I can get it to work perfectly with only one number, but when I try more than one I run into the problem. Do I need to somehow concatenate the responses together before encoding them? Or is there a more efficient way to run this?
private function retrieve_standards_one(){
$dbh = $this->connect();
for($x = 0; $x < (count($this->grades)); $x++){
$stmt = $dbh->prepare("SELECT code, standard_one_id
FROM standard_one
WHERE grade_id = :grade_id
ORDER BY standard_one_id");
$stmt->bindParam(':grade_id', $this->grades[$x], PDO::PARAM_STR);
$stmt->execute();
$stnd = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
$json = json_encode($stnd);
return $json;
}
Just use an array to store the results and encode the array
private function retrieve_standards_one(){
$dbh = $this->connect();
$data = array();
for($x = 0; $x < (count($this->grades)); $x++){
$stmt = $dbh->prepare("SELECT code, standard_one_id
FROM standard_one
WHERE grade_id = :grade_id
ORDER BY standard_one_id");
$stmt->bindParam(':grade_id', $this->grades[$x], PDO::PARAM_STR);
$stmt->execute();
$data[] = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
$json = json_encode($data);
return $json;
}
The problem is this:
$stnd = $stmt->fetchAll(PDO::FETCH_ASSOC);
Each time you go through the loop, you overwrite the contents of $stnd. So yes, in order for it to work properly, you'd need to instead append each individual result to an overall array, and then encode the array.
Here's a rewritten version of your function that both utilizes an array and also doesn't unnecessarily re-prepare the query each loop iteration:
private function retrieve_standards_one(){
$dbh = $this->connect();
$stmt = $dbh->prepare("SELECT code, standard_one_id
FROM standard_one
WHERE grade_id = :grade_id
ORDER BY standard_one_id");
$stnd = array();
for($x = 0; $x < (count($this->grades)); $x++){
$stmt->bindParam(':grade_id', $this->grades[$x], PDO::PARAM_STR);
$stmt->execute();
$stnd[] = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
return json_encode($stnd);
}
Note: the $stnd = array(); line is not strictly necessarily, but it'll prevent things from crashing if $this->grades ever has 0 elements in it.
If you’re wanting to pass an array of numbers, then you can do this:
<?php
$grades = array(1,2,3,4,5);
private function retrieve_standards_one($grades)
{
// ensure only numbers get into the SQL statement
$grade_ids = array();
foreach ($grades as $grade) {
if (is_numeric($grade)) {
$grade_ids[] = $grade;
}
}
$grade_ids = implode(',', $grade_ids);
$dbh = $this->connect();
$sql = "SELECT code, standard_one_id
FROM standard_one
WHERE grade_id IN ($grade_ids)
ORDER BY standard_one_id";
$stmt = $dbh->query($sql);
$stmt->execute();
$stnd = $stmt->fetch(PDO::FETCH_ASSOC);
$json = json_encode($stnd);
return $json;
}
I found this http://net.tutsplus.com/tutorials/php/the-problem-with-phps-prepared-statements/
and it works really good to have it in a seperate php file which my other files calls to with a query as argument.
Is it possible to make something similar with other queries like insert and update?
This is the updated example:
$params is an array.
function insertToDB($params, $db) { //Pass array and db
$fields = array();
$conn = new mysqli('localhost', 'root', 'root', 'db') or die('XXX');
$stmt = $conn->stmt_init();
$stmt->prepare("SELECT * FROM ".$db);
$stmt->execute();
$meta = $stmt->result_metadata();
while ($field = $meta->fetch_field()) {
$fields[] = $field->name;
}
$fields = implode(", ", $fields);
$placeholders = implode(',', array_fill(0, count($params), '?'));
$types = '';
foreach($params as $value) {
$types.= substr(strtolower(gettype($value)), 0, 1);
}
$ins = "INSERT INTO MYDB (".$fields.") VALUES (".$placeholders.")";
$bind_names[] = $types;
for ($i = 0; $i < count($params); $i++) {
$bind_name = 'bind' . $i;
$$bind_name = $params[$i];
$bind_names[] = &$$bind_name;
}
if ($stmt->prepare($ins)) {
call_user_func_array(array($stmt,'bind_param'),$bind_names);
$insresult = $stmt->execute();
}
return $insresult;
$stmt->close();
}