PHP $array[]=$content not working as it ought - php

Okay, I have been tearing my hair (and beard) out at this one for a good hour or more now. I can't work out why it isn't working, particularly as it's exactly the same code I use elsewhere which does work.
$sql = "SELECT * FROM `aio_log` ORDER BY `log_timestamp` DESC LIMIT 10;"; // A 'WHERE' will be put in here
$logs = array();
$one_log = array();
if ($stmt = $mysqli->prepare($sql)) {
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($one_log['id'], $one_log['timestamp'], $one_log['headline'],
$one_log['text'], $one_log['link'], $one_log['font_awesome'],
$one_log['type']);
while ($stmt->fetch()) {
if ($one_log['link'] == "") $one_log['link'] = '#';
// print_r($one_log); shows the expected output of the database row.
$logs[] = $one_log;
//array_push($logs, $one_log); // gives the same - incorrect - response as the above line
}
}
print_r($logs); // Shows the right number of returned rows from the database, but all showing
// an identical content of the last database row returned.
Probably the only difference between this code and code I've used elsewhere is that this one doesn't have any binded parts of the SQL statement as it's a simple 'select everything no matter what' statement, but as the print_r($one_log) bit works fine, I cannot see this being the issue. The issue is obviously somewhere in the $logs[] = $one_log bit, but as I've used it elsewhere, and get exactly the same result using array_push, I'm at my wits end here!
Ideas folks?

This is very strange. The assignment
$logs[] = $one_log;
is supposed to make a copy of $one_log when it pushes it onto the array. But apparently this isn't interacting as expected with the fact that bind_param binds references to the variables -- when you fetch the new row, the references are apparently referring to the copy as well as the original. This is probably a weird consequence of the way that PHP uses copy-on-write; updating the reference seems not to be considered a write that triggers the copy.
I suggest you use normal variables instead of the $one_log array.
$stmt->bind_result($id, $timestamp, $headline, $text, $link, $font_awesome, $type);
and then in the fetch loop use:
$logs[] = array('id' => $id, 'timestamp' => $timestamp, 'headline' => $headline,
'text' => $text, 'link' => $link, 'font_awesome' => $font_awesome,
'type' => $type);

Related

Running sql query inside loop

I store the array into session for easily to retrieve and work.
$responses = session('get_all_response');
$responses contains 30 records maximum.
I aiming to make the pushing of data into the array more fast. Because if I have 10 records in $responses (array) it takes 30secs to load all the possible info regarding each content of that array (But the real thing is. The count of records in an array is more likely 30 maximum)
I loop inside the array
foreach($responses as $res)
{
$bo_images = DB::select('SELECT
image.bo_hotel_code,
image.bo_image_type_code,
image.bo_path,
imagetypes.bo_content_imagetype_description
FROM
bo_images AS image
RIGHT JOIN bo_content_imagetypes AS imagetypes
ON imagetypes.bo_content_imagetype_code = image.bo_image_type_code
WHERE image.bo_hotel_code = "'.$res['code'].'" AND image.bo_image_type_code = "COM" LIMIT 1');
if($bo_images != null)
{
foreach($bo_images as $row)
{
$responses[$res['code']]['information']['bo_images'] = array(
'image_type_code' => $row->bo_image_type_code,
'image_path' => 'http://photos.hotelbeds.com/giata/'.$row->bo_path,
'image_type_description' => $row->bo_content_imagetype_description,
);
}
}
$bo_categories = DB::select('SELECT
a.category_code,
b.bo_content_category_description
FROM
bo_hotel_contents AS a
RIGHT JOIN bo_content_categories AS b
ON b.bo_content_category_code = a.category_code
WHERE a.hotel_code= "'.$res['code'].'"');
if($bo_categories != null)
{
foreach($bo_categories as $row)
{
$responses[$res['code']]['information']['rating'] = array(
'description' => $row->bo_content_category_description,
);
}
}
}
In every loop, there is a code in there that will hold the key to get the contents inside the database.
then after that, it will push the content into that array that equal to the index of the array.
Otherwise. It is a success. But I know this is not the proper way of doing it. I know there is much better to do this.
Any help is so much appreciated
I'm not familiar with Laravel, so I don't know if prepared statements work with it, but you should do something to clean &/or verify the $res['code'] to make sure it is an integer, assuming that's what it's supposed to be.
First, prepare a string for an WHERE IN clause.
$str = "";
foreach ($responses as $res){
$str .= ','.$res['code'];
}
$str = substr($str,1); // to remove the comma
Then you'll need to change your query to use the IN statement.
WHERE a.hotel_code IN({$str})
I'm guessing image.bo_hotel_code refers to $res['code']. But in case it doesn't, you could modify your SELECT statement (if memory serves):
$code = $res['code'];
SELECT {$code} as code,
image.bo_hotel_code,
image.bo_image_type_code,
...
Then you'll loop over the results and put them into the array in the same manner, where $row['code'] would refer to the code used to select it. It should be MUCH faster than running repeated queries, and there should be one row for each code in the IN statement.

MySQLI returns nothing when some variables are inserted in array

Hello I am trying to fetch data from my database using this code:
public function getAllConstitutionPages($id){
$result = $this->conn->prepare("SELECT para.id, para.pageFk,
para.title, para.subtitle, para.paragraph
FROM `constitutionpage_tb` page
JOIN constitutionpageparagraph_tb para ON para.pageFk = page.id
WHERE page.constitutionFk IN (?)");
$result->bind_param("s", $id);
$result->execute();
$response["pages"] = array();
$result->bind_result($id, $pageFk, $title, $subTitle, $paragraph);
while($row = $result->fetch())
{
$page = array();
$page["id"] = $id;
$page["pageFk"] = $pageFk;
$page["title"] = $title;
$page["subTitle"] = $subTitle;
$page["paragraph"] = $paragraph;
echo.$paragraph;//prints out the paragraph in the browser
$response["pages"][] = $page;
}
return $response;
}
The query selects 5 columns which I bind successfully with bind_result issue comes in with the while loop, for some unknown reasons when I add $page["paragraph"] = $paragraph; the query does not return anything not even an empty pages array, the moment I remove it I get all my data, there is nothing wrong with the query because I have tested it in phpmyadmin and it returns all the 5 columns including paragraph, the last time I had such a problem was because I had 2 a variable in the bind_result with the same name as the page array so it was consuming itself, but in this case I do not, someone help me detect my mistake
Update
After wrestling with the code I tried echoing paragraph from the loop and I realized its echoing successfully, what I cannot understand is why cant it be stored in the array, why is it that when I add it nothing absolutely nothing is returned not even an error message
I solved the problem by reviewing my data in the database, aparently on of the paragraphs has a - that had not been escaped.

Workaround for nested while->fetch

Good day everyone!
Currently I'm trying to find a workaround for my problem. As fair as I am concerned, MySqli doesnt support nested fetch'es, therefore my function doesn't quite work. I've tried to find a fix, but had no luck. My current code:
function viewQuestionnaire($id){
$questionStmt = $this->connection->prepare("SELECT id, type, name FROM TAP_questions WHERE questionnaire_id=?;");
$questionStmt->bind_param("i", $id);
$questionStmt->bind_result($id, $type, $name);
$questionStmt->execute();
$result = array();
while ($questionStmt->fetch()) {
$questions = new StdClass();
$questions->question_id = $id;
$questions->question_type = $type;
$questions->question_options = array();
$questions->question_name = $name;
if($questions->question_type=="2"){
$stmtOptions= $this->connection->prepare("SELECT id, options FROM TAP_options WHERE question_id=?;");
$stmtOptions->bind_param("i", $id);
$stmtOptions->bind_result($qu_id, $qu_opt);
$stmtOptions->execute();
while ($stmtOptions->fetch()) {
$options = new StdClass();
$options->option_id = $qu_id;
$options->option_name = $qu_opt;
array_push($questions->question_options, $options);
}
$stmtOptions->close();
}
array_push($result, $questions);
}
$questionStmt->close();
return $result;
}
As you can see, i'm trying to grab values from database, depending on the question type. If the question type is "2", i need to grab "additional" values from another table. How do i do that?
Vlad
I had more or less exactly this problem two weeks ago and found two working solutions:
1.) Nesting the queries, but using/initializing two different connections for them (even if it's to the same database)
2.) Doing one query first, saving the result in an array and using that array later inside the other query.
If you buffer the result, you can run the second query w/o loosing the result from the first query.
In Mysqli you buffer the result of an executed prepared statement (which by default is unbuffered) via the mysqli_stmt::store_result method.
...
$questionStmt = $connection->prepare(
"SELECT id, type, name FROM TAP_questions WHERE questionnaire_id=?;"
);
$questionStmt->bind_param("i", $id);
$questionStmt->bind_result($id, $type, $name);
$questionStmt->execute();
/* store result */
$questionStmt->store_result();
...
/* free result */
$questionStmt->free_result();
$questionStmt->close();
...

[PHP/MySQL]: Prepared Statement in a loop

My problem seems like a rather small one to me, yet, I cannot figure out a proper solution.
The Setup: I have a table 'city_locations' with the columns 'country', 'city', 'longitude', 'latitude'. The countrys are given by 2-Letter ISO codes. I want them to be full names.
For this, I have imported the table 'countrycodes', containing only the columns 'name' and 'code'.
$namechange = $con->prepare("UPDATE city_locations SET country=? WHERE country=?");
$list = $con->prepare("SELECT name, code FROM countrycodes");
$list->execute();
$list->bind_result($name, $code);
$namechange->bind_param('ss', $name, $code);
while ($list->fetch()){
while ($namechange->execute()) {}
echo "$code is now $name <br>";
}
I succesfully retrieve all pairs in the (outer) while loop.
$namechange->execute(); however doesn't do anything - I tried it with and without the while loop, tried using LIMIT 0, 10000 in the query (though I'm not entirely sure I understand LIMIT right). With and without the while loop, the statement doesn't do anything. With LIMIT 0, 10000 the statement cannot be preapred properly (gives an error).
I also tried to bind the params new in every step of the while loop - didn't seem to do anything either.
When running the same command from my web interface, it works fine. However, in that case, I have to type all 200+ codes manually. Seems like a bit much work.
Thanks a lot for your help,
Kjeld.
EDIT: $con is of type mysqli.
$namechange = $con->prepare("UPDATE city_locations SET country=? WHERE country=?");
$list = $con->prepare("SELECT name, code FROM countrycodes");
$list->execute();
$list->bind_result($name, $code);
while ($list->fetch()){
$namechange->bind_param('ss', $name, $code);
$namechange->execute();
echo "$code is now $name <br>";
}
it will probably solve your problem.

mysql query not running correctly from inside the application

I am completely stumped. Here is my php (CodeIgniter) code:
function mod()
{
$uid = $this->session->userdata('uid');
$pid = $this->input->post('pid');
if ($this->_verify($uid,$pid))
{
$name = $this->input->post('name');
$price = $this->input->post('price');
$curr = $this->input->post('curr');
$url = $this->input->post('url');
$query = $this->db->query("UPDATE items SET
name=".$this->db->escape($name).",
price=".$this->db->escape($price).",
currency=".$this->db->escape($curr),",
url=".$this->db->escape($url)."
WHERE pid=".$this->db->escape($pid)." LIMIT 1");
}
header('location: '.$this->session->userdata('current'));
}
The purpose of this code is to modify the properties (name, price, currency, url) of a row in the 'items' table (priary key is pid). However, for some reason, allowing this function to run once modifies the name, price, currency and url of ALL entries in the table, regardless of their pid and of the LIMIT 1 thing I tacked on the end of the query. It's as if the last line of the query is being completely ignored.
As if this wasn't strange enough, I replaced "$query = $this->db->query(" with an "echo" to see the SQL query being run, and it outputs a query much like I would expect:
UPDATE items
SET name = 'newname',
price = 'newprice',
currency = 'newcurrency',
url = 'newurl'
WHERE pid = '10'
LIMIT 1
Copy-pasting this into a MySQL window acts exactly as I want: it modifies the row with the selected pid.
What is going on here???
Now I feel stupid: all it took was seeing my code in a different font. My code has
currency=".$this->db->escape($curr),",
instead of
currency=".$this->db->escape($curr).",
The echoing made it work just fine because apparently you can give echo more than one string, comma separated, and it concatenates them
cries I spent hours on this
I know you answered your own question, but let me just add this to the pile: You're not leveraging CodeIgniter AT ALL in this sort of query - which if you used CI as it's intended, you wouldn't have had that typo. Your query should look like this (among other things):
$query = $this->db->update('items',
array('name' => $this->input->post('name'),
'price' => $this->input->post('price'),
'curr' => $this->input->post('curr')),
array('id' => $this->input->post('id')),
1);
By assembling the query string by hand, you're undoing what CI does for you. Only when you're using some complex JOIN statement should you be writing your own SQL in CI, and even then, you want to use the sprintf PHP function to make sure you're not introducing typos.

Categories