I have a function that uses mysqli function that is as follows:
public function GetProjectOptions()
{
$return = "";
$sql = "SELECT `id`, `project_name` FROM `projects`;";
$rs = static::$link->query($sql);
$return .= '<select class="form-control" name="project">';
while ($result = mysqli_fetch_assoc($rs));
{
$return .= "<option value='" . $result['id'] . "'>" .
$result['project_name'] . "</option>";
}
$return .= '</select>';
return $return;
}
The purpose of this function is to create the options and select that will be used for the Projects on my site, I know that there are 4 projects currently stored in the table, but they do not return in this function, what have I done wrong?
EDIT:
Link to screen output: (http://i.imgur.com/YIYiheH.png)
Link to code output: (http://i.imgur.com/RZsUIwQ.png)
Link to code usage: (http://i.imgur.com/4J9rvd7.png)
(Wouldn't let me do normal links)
I found the problem.
Remove the semi-colon here
while ($result = mysqli_fetch_assoc($rs));
^
that's why it's not throwing an error, because it's considered as valid syntax.
Your loop is being stopped/terminated by it.
What I think Jay and Styphon mean by their comment is that you don't do any error checking within your SELECT query. Are you sure your query is executing properly? I understand this is a relatively simple query and that you're positive there are four projects currently stored in your table, but it's always a good habit to check. Try this:
public function GetProjectOptions()
{
$return = "";
$sql = "SELECT `id`, `project_name` FROM `projects`;";
$rs = static::$link->query($sql);
$return .= '<select class="form-control" name="project">';
if($rs){
while ($result = mysqli_fetch_assoc($rs));
{
$return .= "<option value='" . $result['id'] . "'>" . $result['project_name'] . "</option>";
}
$return .= '</select>';
}else{
$message = 'Invalid query: ' . mysqli_error() . "\n";
$message .= 'Whole query: ' . $sql;
die($message);
}
return $return;
}
I hope this helps!
Related
I'm trying to dynamically generate a form from a database so that I can simply login and make changes, as well as track the votes. The form is generating fine but, I can't for the life of me figure out how to get the id from the array to post in with the data. The only successful attempt set the last one as all of their topic_id because I tried to define it in the while statement.
<?php $cat_set = fetch_categories();
if (!isset($business_name)) {
$business_name = ''; }
while($categories = mysqli_fetch_assoc($cat_set)) {
echo '<div class="category">'. "<h3>" . "Best of the Best"
.' ' . ucfirst($categories["cat_name"]) . ' ' . "</h3>";
$topic_set = get_topics_for_cat($categories["cat_id"]);
while($topics = mysqli_fetch_assoc($topic_set)) {
$topic_name = $topics["topic_name"];
echo '<div class="field">' . '<label for=' .
$topics['topic_id'] . '">' . ucfirst($topic_name) . ":" . '</label>';
echo '<input type="text"' . 'id="' .
$topics['topic_id'] . '"' . 'name="'
. $topics["topic_id"] . '"' . 'value="' .
$business_name . '"></div>';
}
echo "</div>";
}
?>
<input type="submit" value="Submit" id="submit" name="submitform"></form>
</div>
<pre>
<?php
$user_id = 3000;
if (isset($_POST['submitform'])) {
print_r($_POST);
foreach ($_POST as $business_name) {
$filtered_business_name = mysqli_real_escape_string($dbc,
$business_name);
$query = "INSERT INTO votes (";
$query .=" business_name, topic_id, user_id";
$query .= ") VALUES (";
$query .=" '$filtered_business_name', '$topics['topic_id']',
'$user_id'";
$query .=")";
$votes = mysqli_query($dbc,$query);
So more specifically I guess, what would be the best way to get $topics['topic_id'] into my query? I've tried to escape it and about everything I can think of.
Wrap the variable in curly brackets:
$query .=" '$filtered_business_name', '{$topics['topic_id']}', '$user_id'";
Do as follows:
$topic = $topics['topic_id'];
$query .=" '$filtered_business_name', '$topic', '$user_id'";
I must have just been using it wrong. I'd made so many edits and things that my own stuff didn't make sense, so I reversed a bunch and tried the key=>value thing ... and it worked right off. Now the query is:
if (isset($_POST['submitform'])) {
foreach($_POST as $key=>$value) {
$filtered_business_name = mysqli_real_escape_string($dbc, $value);
$query = "INSERT INTO votes (";
$query .=" business_name, topic_id, user_id";
$query .= ") VALUES (";
$query .=" '$filtered_business_name', '$key', '$user_id'";
$query .=")";
$votes = mysqli_query($dbc,$query);
confirm_query($votes);
}
}
Thank you everyone for your help, hopefully this will help someone with their crappy form building in the future.
I am trying to pull all the column names from my database 'settings' and list them in PHP.
A bit of research has come up with the following:
SHOW COLUMNS FROM settings
but I don't know how to go about listing these off through PHP.
it would be helpful if any code posted was a prepared statement format, but not required.
Here is my PHP, it's giving me this error:
Notice: Undefined index: sThumbWidth in /home/demomycm/public_html/subdomains/mercury/eshop/library/classes/class.settings.php on line 204
for every field in my database.
$loadColumns = array();
$query = "SHOW COLUMNS FROM settings";
$result = $this->glob->dbConn->query($query);
if($this->glob->dbConn->errno) {
trigger_error('An error occurred whilst loading counties from the database.' . PHP_EOL . 'Query: ' . $query . PHP_EOL . 'Error[' . $this->glob->dbConn->errno . ']: ' . $this->glob->dbConn->error, E_USER_WARNING);
} elseif($result->num_rows) {
while($row = $result->fetch_assoc()) {
$loadColumns[$row['Field']];
}
return $loadColumns;
}
$loadColumnsHtml = '';
$loadColumns = $this->Settings->LoadColumns();
foreach($loadColumns as $i => $field) {
$loadColumnsHtml .= '<div class="home-stat-small-link">' . ($i + 1) . '. <strong>' . $field['Field'] . '</strong>.</div>';
}
use describe
DESCRIBE my_table;
Or in newer versions you can use INFORMATION_SCHEMA:
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'my_database' AND TABLE_NAME = 'my_table';
In your code you have $loadColumns as an array.
This line does nothing: $loadColumns[$row['Field']];
Basically your getting the value in $loadColumns with the key associated with $row['Field'] and not assigning anything.
You want something like this perhaps for that line:
array_push($loadColumns,$row['Field']);
Full code below
$loadColumns = array();
$query = "SHOW COLUMNS FROM settings";
$result = $this->glob->dbConn->query($query);
if($this->glob->dbConn->errno) {
trigger_error('An error occurred whilst loading counties from the database.' . PHP_EOL . 'Query: ' . $query . PHP_EOL . 'Error[' . $this->glob->dbConn->errno . ']: ' . $this->glob->dbConn->error, E_USER_WARNING);
} elseif($result->num_rows) {
while($row = $result->fetch_assoc()) {
array_push($loadColumns,$row['Field']); //<-- this line has been changed
}
return $loadColumns;
}
$loadColumnsHtml = '';
$loadColumns = $this->Settings->LoadColumns();
foreach($loadColumns as $i => $field) {
$loadColumnsHtml .= '<div class="home-stat-small-link">' . ($i + 1) . '. <strong>' . $field['Field'] . '</strong>.</div>';
}
On MySQL connection (deprecated) you can use:
mysql_list_fields
On PDO (recommend) use:
$query = $dbh->prepare("DESCRIBE tablename");
$query->execute();
$tableFields = $query->fetchAll(PDO::FETCH_COLUMN);
On PDO you can also use PDOStatement::getColumnMeta(). But it has the status: EXPERIMENTAL
I have a function loadContent() that when called, queries a database, formats the data and should return the result. This is being used to build a very primitive CMS and this function is used to load the articles from the database.
Here is the function is question:
$articles = mysql_query("SELECT `id`, `name`, `content`, `keywords`, `description`, `access_level` FROM `tb_articles` WHERE `page_id`='$pageID'");
if(!$articles){
die('Error!: ' . mysql_error());
}
while($arts = mysql_fetch_assoc($articles)){
$content .= '<div class="article" id="art-' . $arts['id'] . '">';
$content .= '<h1>' . $arts['name'] . '</h1>';
$content .= $arts['content'];
$content .= '</div>';
}
return $content;
}else{
My problem is that nothing is being returned. The SQL is verified, it should return two rows. I have commented out everything in the loop and added the line $content .= 'test'; and changed the return statement to echo $content; and the function successfully echo'ed "test" twice. So whats wrong with what I have done?
Thanks for helping me out, I'm pretty new to PHP.
UPDATE:
The post now represents all valid changes.
I got somewhere with var_dump. I dumped $content just before the return statement. All of the articles in the database (2 of them) were displayed inside of string(2445) "". This confirms there are no problems with the query. I am now thinking it has something to do with the return statement.
Not sure if this is related, but it doesn't look like you ever close the first div tag. You don't close the id attribute quote either (opened with an apostrophe, and you concatenate a quote).
More specifically:
... id='art-" . $arts['id'] . "'></div>";
Try updating your code to this:
function loadContent(){
$content = '';
$pageID = 1;
//
$articles = mysql_query("SELECT `id`, `name`, `content`, `keywords`, `description`, `access_level`
FROM `tb_articles`
WHERE `page_id`='$pageID'");
// you only need the associative array
while($arts = mysql_fetch_array($articles, MYSQL_ASSOC)){
// close your tag properly and use the concat operator
$content .= '<div class="article" id="art-' . $arts['id'] . '">';
$content .= '<h1>' . $arts['name'] . '</h1>';
$content .= $arts['content'];
$content .= '</div>';
}
return $content;
}
Also you could try running mysql_error() after your call to mysql_query() to see if anything goes wrong.
Another thing that you should check is so that there actually is a row with page_id equal to 1 in your database. You should also make sure that your column names are correct.
$content .= "<div class='article' id='art-" . $arts['id'] . '"';
and it should be
$content .= "<div class='article' id='art-" . $arts['id'] . "'";
try this
error_reporting(E_ALL);
ini_set("display_errors", 1);
function loadContent(){
$content = '';
$pageID = 1;
$myQuery = "SELECT `id`, `name`, `content`, `keywords`, `description`, `access_level` FROM `tb_articles` WHERE `page_id`='{$pageID}'";
echo $myQuery;
$myQuery = "SELECT `id`, `name`, `content`, `keywords`, `description`, `access_level` FROM `tb_articles` WHERE `page_id`=" . $pageID;
echo $myQuery;
$articles = mysql_query($myQuery) or die("Error found with the Query" . mysql_error());
while($arts = mysql_fetch_assoc($articles)){
$content .= "<div class='article' id='art-" . $arts['id'] . '"';
$content .= '<h1>' . $arts['name'] . '</h1>';
$content .= $arts['content'];
$content .= '</div>';
}
return $content;
}
Try and tell me, and I'll update with the explanation, if it works.
UPDATE
The code has been updated, there are two queries now, execute each one alone and check.
I'm currently updating my PHP knowledge and I've stumbled upon a problem whilst grabbing data from my database.
The problem I have in itself could probably be sorted with the max_connection setting (yes, I've searched around), but I believe it might be a work-around, since I don't want to change base settings, if not so needed.
I have three "steps" in my little "ladder";
My main is a ladder, every ladder has one (or more) step and every step has one (or more) modules.
So what I'm trying to do is a function that retrieves all of these and shows them. Now, every function has a connection to my database; where the function runs its query and then closes. My first clue was to close the database between every function, which I did - but since I'm retrieving my code "all at once", this doesn't work (see code).
How would I go about making one database connection (maybe in a function) and calling it once, and then retrieving all the information, without opening new connections?
I hope you have all information required to answer my questions, and I hope I'm posting this in a stack overflow way.
Thank you in advance.
P.S: Dunno if I used this code tool right, it looks structured, but it doesn't have highlights?
CODE:
<?php
echo displayResult();
function displayResult() {
$db = new mysqli ('localhost', 'website', 'dog', 'nplus');
$sql = 'SELECT * FROM ladders';
$result = $db->query($sql);
$r = '';
$r .= '<table>';
while ($row = $result->fetch_object()) {
$r .= '<tr>';
$r .= '<td>' . htmlspecialchars($row->ladderID) . '</td>';
$r .= '<td>' . htmlspecialchars($row->ladderName) . '</td>';
$r .= '<td>' . htmlspecialchars($row->created) . '</td>';
$r .= displayAssociateStep($row->ladderID);
$r .= '<tr><td> </td></tr>';
}
$r .= '</table>';
$db->close();
return $r;
}
function displayAssociateStep($ladderID) {
$r = '';
$db = new mysqli ('localhost', 'website', 'dog', 'nplus');
$sql = 'SELECT * FROM steps WHERE ladderID = '. $ladderID ;
$result = $db->query($sql);
$r = '';
while ($row = $result->fetch_object()) {
$r .= '<tr>';
$r .= '<td></td>';
$r .= '<td></td>';
$r .= '<td>' . htmlspecialchars($row->stepName) . '</td>';
$r .= '<td>' . htmlspecialchars($row->created) . '</td>';
$r .= '</tr>';
}
$db->close();
return $r;
}
?>
You only need to connect to the database once, and pass it around as an argument, like so:
<?php
function displayResult($db) {
$sql = "
SELECT *
FROM ladders
";
$result = $db->query($sql);
// ADD ERROR CHECKING HERE
// What happens if the query fails?
$r = '<table>';
while ($row = $result->fetch_object()) {
$r .= '<tr>';
$r .= '<td>' . htmlspecialchars($row->ladderID) . '</td>';
$r .= '<td>' . htmlspecialchars($row->ladderName) . '</td>';
$r .= '<td>' . htmlspecialchars($row->created) . '</td>';
$r .= '</tr>';
$r .= displayAssociateStep($db, $row->ladderID);
$r .= '<tr><td colspan="3"> </td></tr>';
}
$r .= '</table>';
return $r;
}
function displayAssociateStep($db, $ladderID) {
// Are you 100% certain $ladderID is always safe to use in a query?
// Does it need escaping?
$sql = "
SELECT *
FROM steps
WHERE ladderID = $ladderID
";
$result = $db->query($sql);
// ADD ERROR CHECKING HERE
// What happens if the query fails?
$r = '';
while ($row = $result->fetch_object()) {
$r .= '<tr>';
$r .= '<td></td>';
$r .= '<td>' . htmlspecialchars($row->stepName) . '</td>';
$r .= '<td>' . htmlspecialchars($row->created) . '</td>';
$r .= '</tr>';
}
return $r;
}
// Connect once
$db = new mysqli ('localhost', 'website', 'dog', 'nplus');
// Pass the connection in as an argument
echo displayResult($db);
// Close the connection
$db->close();
I would say... pass the $db variable you got in displayResult to displayAssociateStep, as an added parameter. Then you don't need to open/close connexion in displayAssociatesStep anymore.
Is it what you want to do?
I've been learning about DRY code and my code isn't DRY...
For example, I have a custom CMS and I save basically a name, content and a publish status for a few things... like an article, a user, a event. To submit a form, I submit to a file (process.php) which has a switch in it like so:
switch($_POST['process']) {
case 'speaker':
if($_POST['speaker_id']) {
$sql = '
UPDATE speakers
SET speaker_name="' . mysql_escape_string($_POST['speaker_name']) . '",
speaker_content="' . mysql_escape_string($_POST['speaker_content']) . '",
speaker_status="' . $_POST['speaker_status'] . '"
WHERE speaker_id="' . $_POST['speaker_id'] . '"
LIMIT 1
';
} else {
$sql = '
INSERT INTO speakers
SET speaker_name="' . mysql_escape_string($_POST['speaker_name']) . '",
speaker_content="' . mysql_escape_string($_POST['speaker_content']) . '",
speaker_status="' . $_POST['speaker_status'] . '"
';
}
mysql_query($sql);
if($_POST['speaker_id']) {
header('Location: speakers?speaker_id=' . $_POST['speaker_id']);
} else {
header('Location: speakers?speaker_id=' . mysql_insert_id);
}
break;
case 'event':
if($_POST['event_id']) {
$sql = '
UPDATE events
SET event_name="' . mysql_escape_string($_POST['event_name']) . '",
event_content="' . mysql_escape_string($_POST['event_content']) . '",
event_status="' . $_POST['event_status'] . '"
WHERE event_id="' . $_POST['event_id'] . '"
LIMIT 1
';
} else {
$sql = '
INSERT INTO events
SET event_name="' . mysql_escape_string($_POST['event_name']) . '",
event_content="' . mysql_escape_string($_POST['event_content']) . '",
event_status="' . $_POST['event_status'] . '"
';
}
mysql_query($sql);
if($_POST['event_id']) {
header('Location: events?event_id=' . $_POST['event_id']);
} else {
header('Location: events?event_id=' . mysql_insert_id);
}
break;
case 'article':
if($_POST['article_id']) {
$sql = '
UPDATE articles
SET article_name="' . mysql_escape_string($_POST['article_name']) . '",
article_content="' . mysql_escape_string($_POST['article_content']) . '",
article_status="' . $_POST['article_status'] . '",
article_modified="' . $_POST['article_modified'] . '"
WHERE article_id="' . $_POST['article_id'] . '"
LIMIT 1
';
} else {
$sql = '
INSERT INTO articles
SET article_name="' . mysql_escape_string($_POST['article_name']) . '",
article_content="' . mysql_escape_string($_POST['article_content']) . '",
article_status="' . $_POST['article_status'] . '"
';
}
mysql_query($sql);
if($_POST['article_id']) {
header('Location: articles?article_id=' . $_POST['article_id']);
} else {
header('Location: articles?article_id=' . mysql_insert_id);
}
break;
}
Despite some basic variations, like different table names and column names, and perhaps there sometimes being a couple more or less columns to populate, the code is literally the same and programming like this feels more like data entry than creativity.
I imagine there's a way to create a class for this so that all the below code could be achieved in 1/3 the amount. Is there some sort of streamlined mysql insert / update method/strategy?
In my head, I'm thinking if I name all my inputs the same as they are in the table, ie if the column is called 'speaker_name' and the input is..
<input type="text" name="speaker_name" />
...I wonder if I could have a function which went through the $_POST array and simply updated the appropriate fields. Is this sound logic?
Perhaps I would have a hidden input in the form which was the 'table' variable which let the function know which table to update and it takes care of the rest.
Excuse me while I just thought out-loud. Any ideas would be really cool!
My newbie solution
Here's what I have i got working
if($_POST['id']) {
$sql = 'UPDATE ';
} else {
$sql = 'INSERT INTO ';
}
// number of rows in array
$total = count($_POST);
// number of commas = total of values minus 1
$commas = $total - 1;
// starting number
$count = 1;
foreach ($_POST as $key => $value) {
if($count == 1)
{
$sql .= mysql_real_escape_string($value) . ' SET ';
}
else
{
if( $count < $total )
{
$sql .= $key . '="' . mysql_real_escape_string($value) . '"';
if($count != $commas)
{
$sql .= ', ';
}
}
elseif( $_POST['id'] )
{
$sql .= ' WHERE ' . $key . '="' . mysql_real_escape_string($value) . '"';
}
}
$count = $count + 1;
}
mysql_query($sql);
if($_POST['id']) {
header('Location: ' . $_POST['process'] . '?id=' . $_POST['id'] . '');
} else {
header('Location: ' . $_POST['process'] . '?id=' . mysql_insert_id());
}
To do this means my form designs need to have a pretty strict setup ie the first hidden input holds the table name, the last input is the id number of the row in the table being edited (if it exists).
I know its far from good... but a lot better than the hundreds of lines it previously took.
1) some flaws in your concept
every piece of data you're going to put into quotes in your query, should be processed with
mysql_real_escape_string, as you cannot know what can be inside.
never use a table name passed from the client side. there can be malicious code instead of mere table name as well.
same for the field names. every identifier should be hardcoded in your script.
2) as for the DRY - it's simple. just note similar parts in your code and put them into function. only fields differ? okay, make a function that take fields list and produce an SQL statement of them.
Luckily, Mysql let us use similar syntax for both insert and update. So, a very simple function like this one can help:
function dbSet($fields) {
$set='';
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$set.="`$field`='".mysql_real_escape_string($_POST[$field])."', ";
}
}
return substr($set, 0, -2);
}
So, you can make your code shorter:
case 'speaker':
$table = "speakers";
$fields = explode(" ","speaker_name speaker_content speaker_status");
if(isset($_POST['speaker_id'])) {
$id = intval($_POST['speaker_id']);
$query = "UPDATE $table SET ".dbSet($fields)." WHERE id=$id";
} else {
$query = "INSERT INTO $table SET ".dbSet($fields);
}
mysql_query($sql) or trigger_error(mysql_error().$query);
if($_POST['speaker_id']) $id = mysql_insert_id();
header('Location: speakers?speaker_id='.$id);
break;
if all your actions are such alike, you can make more high leveled functions:
case 'speaker':
$table = "speakers";
$fields = explode(" ","speaker_name speaker_content speaker_status");
if(isset($_POST['speaker_id'])) {
$id = intval($_POST['speaker_id']);
dbUpdate($table,$fields,$id);
} else {
$id = dbInsert($table,$fields);
}
header('Location: speakers?speaker_id='.$id);
exit;
break;
and even more high level
case 'speaker':
$table = "speakers";
$fields = explode(" ","speaker_name speaker_content speaker_status");
$id = dbMagic();
header('Location: speakers?speaker_id='.$id);
exit;
break;
But I won't go into that. I'd stop at 1st option, because it's pretty straightforward and there are always some little things not fit into such a broad concept.
While your alignment of column names and perhaps a hidden form field for table name would be quicker to code and more elegant to code against you would be opening yourself up to someone spoofing an HTML file to control the inserts to a table! Consider refactoring in other ways to optimize your library. Keep thinking / you're bound to come up with a better solution within the context of your problem domain.
Usually, one has some base models to do this, for example (don't be to harsh about it's failtings, I just want to give a short example):
class Speaker {
function __construct($data){
foreach($data as $key => $value) $this->$key = $value;
}
function save(){
$query =
($this->speaker_id ? 'UPDATE ':'INSERT INTO').' speakers '
."SET speaker_name='%s',
speaker_content='%s',
speaker_status='%s'"
.($this->speaker_id ? ' WHERE speaker_id=%d ':'');
mysql_query(sprintf($query(
mysql_real_escape_string($this->speaker_name),
mysql_real_escape_string($this->speaker_content),
mysql_real_escape_string($this->speaker_status),
intval($this->speaker_id)));
if(!$this->speaker_id) $this->speaker_id = mysql_insert_id();
}
}
And then:
switch($_POST['process']) {
case 'speaker':
$speaker = new Speaker($_POST);
$speaker->save();
header('Location: /speakers?speaker_id='.$speaker->speaker_id);
But for new projects, I would suggest a more complete MVC pattern (where Event & Speaker can be subclasses from some base databasemodel, possibly able to generate some form based on settings), and use prepared statements, they will make your sql queries easier & safer. never use addslashes, for good ol' mysql_query use mysql_real_escape_string