I'm writing an application in PHP and am currently designing a form which includes two drop-down style boxes. These boxes need to be populated with data from a database I've got access to. The database contains two stored procedures, each returning the data to populate one of the drop-down boxes.
In my PHP, I prepare the queries I need to run like:
$viewLevelQuery = "CALL pr_getViewLevels();";
$publishLevelQuery = "CALL pr_getPublishLevels();";
And, in the lines immediately following, execute them like:
$con=mysqli_connect($host,$user,$pass,$dbnm);
$viewLevelResult = mysqli_query($con,$viewLevelQuery);
$publishLevelResult = mysqli_query($con,$publishLevelQuery);
mysqli_close($con);
Later in the PHP, I render and populate the drop-down boxes like:
echo "<div class='col-sm-10'>
<select class='form-control' id='viewLvl' name='viewLvl'>";
while($row=mysqli_fetch_array($viewLevelResult))
{
echo "<option>".$row['viewName']."</option>";
}
echo "</select> </div>";
And:
echo "<div class='col-sm-10'>
<select class='form-control' id='pubLvl' name='pubLvl'>";
while($row=mysqli_fetch_array($publishLevelResult))
{
echo "<option>".$row['publishName']."</option>";
}
echo "</select> </div>";
My issue is that only one of the boxes is being populated and it seems as though only the first of the MySQLi_query calls is being performed. No error is returned and the page continues to render as it should.
If the MySQLi_query lines at the beginning are switched, the other drop-down box is populated as expected which leads me to believe the queries to the database are correct.
Does the call to MySQLi_query "consume" the $con variable? If I execute the queries from PHP like:
$con=mysqli_connect($host,$user,$pass,$dbnm);
$viewLevelResult = mysqli_query($con,$viewLevelQuery);
$con=mysqli_connect($host,$user,$pass,$dbnm);//NOTICE Extra call to connect
$publishLevelResult = mysqli_query($con,$publishLevelQuery);
mysqli_close($con);
Both boxes get populated correctly. Doing this, however, doesn't feel right. Am I missing something? Or is this the way to go?.
Many thanks
EDIT: In case anyone with similar issues stumbles across this, as discovered below the error I was getting was because of mysqli's use of unbuffered queries. This means that it can't hold the results of two queries at once and so this memory needs to be freed once you have stored/used the results in your PHP. I simply copied the resultset to a PHP array and then included a:
while(mysqli_next_result($con))
{
mysqli_free_result($con);//Clears results
}
after each query. My understanding of what is going on is a little flakey, but this seems to make sense. It works, anyhow.
Related
I have a MySQL stored procedure that updates data across a set of tables (basically for one record in the principal table and related records in a set of child tables). It's called via AJAX through a PHP function. (That is, the AJAX call is to a PHP page, which ultimately calls this SP.) It was working fine, but now I'm trying to make it do one more thing and running into the "Commands out of sync; you can't run this command now" error.
The change is to store one more item in the principal table, but to do so may require adding an item to a child table (called ActionTopic). The page lets the user either choose from a dropdown or type in a new value. I've added two parameters to the SP: one is the PK chosen in the dropdown, the other is the new value typed in. In the SP, I've added the code below. It checks whether there was a new value typed in. If so, it calls another SP that checks whether the value typed in is already in the table and, if not, adds it. (I've tried with the code to check and add the record inline rather than in a separate SP and I have the same problem.)
if cNewTopic <> '' then
-- First, make sure the new topic isn't already there
call aoctest.AddActionTopic(cNewTopic);
-- SELECT #iTopicID := iID FROM ActionTopic WHERE UPPER(Description) = UPPER(cNewTopic);
SET #iTopicID = LAST_INSERT_ID();
else
SET #iTopicID = Topic;
end if;
The page works if the user makes a choice from the dropdown. The problem only occurs when the user types in a new value. Even when I get the error, everything else works as expected. The new value is added to the child table, and the parent table and other children are updated as expected.
Interestingly, if I call the SP in MySQL Workbench with the same parameters (after ensuring that the new value isn't in the new table), it runs without error. The only odd thing I've noticed is that I get two rows in the Output section of MySQL Workbench rather than one. Both show the call to the SP. The first shows "1 row(s) returned" and a period of time, while the second shows "0 row(s) returned" and "-/0.000 sec". A call to the SP in MySQL Workbench where the new value is already in the table also shows two rows in the Output section, but the second one shows "1 row(s) returned".
Not sure whether any of the other code is needed here. If you think I need to show more, please ask.
UPDATE: Based on the comment from Pete Dishman, I took a harder look at where the error is occurring. It's not the original SP call giving an error. It's the next call to MySQL, which is still inside the Ajax call.
The code processing the result already had this code:
//not sure why next line should be needed.
mysqli_next_result($conn);
I tried both simply doubling the call to mysqli_next_result (that is, two in a row) and putting it into a loop along the lines Pete suggested. With two calls, I still get the same error. With a loop, I wait 30 seconds and then get error 500: Internal server error.
UPDATE 2: I tried with a loop for mysqli_more_results() (similar to the one in Pete Dishman's reply) and echoing a counter inside the loop. The code brought my internet connection to a crawl and I finally had to break out of it, but there were dozens of iterations of the loop. Just tried the following:
mysqli_free_result($result);
$result = mysqli_store_result($conn);
mysqli_free_result($result);
if (mysqli_more_results($conn)) {
$result = mysqli_store_result($conn);
mysqli_free_result($result);
}
$allresult = getsubmissions($conn);
Found a noticeable delay before it failed.
Even if you can't tell me what's wrong, I'd appreciate ideas for how to debug this.
This may be because the stored procedure is returning multiple result sets (the two rows in workbench).
When querying from php you need to retrieve both result sets before you can send another query, otherwise you get the "commands out of sync" error.
The documentation seems to imply this is only the case when using mysqli_multi_query but we have it in our code when using mysqli_real_query.
Our query code is along the lines of:
mysqli_real_query($conn, $sql);
$resultSet = mysqli_store_result($conn);
while (!is_null($row = mysqli_fetch_array($resultSet, MYSQLI_BOTH)))
{
$results[] = $row;
}
mysqli_free_result($resultSet);
// Check for any more results
while (mysqli_more_results($conn))
{
if (mysqli_next_result($conn))
{
$result = mysqli_store_result($conn);
if ($result !== FALSE)
{
mysqli_free_result($result);
}
}
}
return $results;
The code would be different obviously if you're using PDO, but the same principle may apply (See http://php.net/manual/en/pdostatement.nextrowset.php)
I've solved my own problem by reworking the code that processes the result as follows:
if (mysqli_more_results($conn)) {
mysqli_free_result($result);
mysqli_next_result($conn);
$result = mysqli_store_result($conn);
mysqli_free_result($result);
if (mysqli_more_results($conn)) {
mysqli_next_result($conn);
$result = mysqli_store_result($conn);
if (!is_null($result) and gettype($result)!== 'boolean') {
mysqli_free_result($result);
}
}
}
$allresult = getsubmissions($conn);
I am just wondering, if possible, the best way to go about allowing users to actually input an SQL query from within a web application.
I have so far got a very simple web application that allows users to view the database tables and manipulate them etc etc..
I wanted to give them an option to actually type queries from within the web app too (SELECT * FROM).. and then display the results in a table. (Exactly the same as a search bar, but I don't think that would cut it, would it?).
I am only using PHP at the moment, is what I'm looking to do possible with just HTML/PHP or will I need the help of other languages?
This may be too complex for me, but if someone could give me a starting point that would be great, thank you.
UPDATE:
From my understanding to answer my question, i need something like:
<form action= Search.php method="POST">
<input type="text" name="Search">
<input type="submit" name"">
Search.php
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$SEARCH = $_POST['Search'];
if (!isset($_POST)) {
$sql = "'%".$_POST['$SEARCH']."%'";
$results = mysqli_query($con, $sql);
echo "<table border ='2'>";
if (mysqli_num_rows($results) !=0) {
while ($row=mysqli_fetch_array($results)) {
echo "<tr><td></td></tr>";
}
echo "</table>";
}else {
echo "Failed! Try another search query.";
}
}
}
?>
At the moment in returns one error:
Undefined index: Search
It's talking about the $SEARCH = $_POST['Search'];
But I thought I am defining that Search, as that's the Search in the form?
Sounds like you're building your own minimalistic version of phpMyAdmin. That's perfectly doable with just PHP and HTML.
A very basic implementation would be a standard HTML form with a textarea, which submits to a PHP script that executes the query and renders a table of the results. You can get the required table column headers from the first result row's array keys if you fetch the results as an associative array.
You may (or perhaps I should say "will") run into situations where users provide a query that returns millions of results. Outputting all of them could cause browsers to hang for long periods of time (or even crash), so you might want to implement some sort of pagination and append a LIMIT clause to the query.
Since the user is providing the SQL query themselves, they need to know what they did wrong so they can correct it themselves as well so you'll want to output the literal error message from MySQL if the query fails.
Allowing users to provide raw SQL queries opens the door to a lot of potential abuse scenarios. If it were my application, I would not want users to use this feature for anything other than SELECT queries, so I would probably have the user-provided queries executed by a MySQL-user that only has SELECT privileges on the application database and not a single other privilege -- that way any user that tries to DROP a table will not be able to.
Undefined index: Search
This error will show only when the PHP is executed for the first time as it's simply expecting "Search" in $_POST.
$_SERVER['REQUEST_METHOD'] checks if the request method is POST it does not check if $_POST have any post data in it.
(Source :$_POST vs. $_SERVER['REQUEST_METHOD'] == 'POST')
But the page is being loading for the first time so it wouldn't have anything in POST.
You can simply avoid it by check if the page is loading for first time, using the "isset()" method.
If its loading for the first time just ignore the further execution of php code and simply show the form to enter the query.
<?php
if(isset($_POST['Search']))
{
`// Query execution code`.
}
?>
<form action= Search.php method="POST">
<input type="text" name="Search">
<input type="submit" name"">
So if the search index is not set in the $_POST it wont execute the php code and will not generate any error.
I'm new to this and I know I'm probably doing this entire thing the wrong way, but I've been at it all day trying to figure it out. I'm realizing there's a big difference between programming a real project of my own rather than just practicing small syntax-code online. So, I lack the experience on how to merge/pass different variables/scopes together. Understanding how to fit everything within the bigger picture is a completely different story for me. Thanks in advance.
What I'm trying to do, is to make the function "selectyacht" output data in a different location from where it's being called (in viewship.php). The output data (in viewship.php) needs to be only certain fields (not everything) returned and those results will be scattered all over the html page (not in a table). In addition to that, I have this variable: "$sqlstatement" (in sqlconn.php) that I'm trying to bring outside the function because I don't want to repeat the connection function every time. I tried a global variable, as much as I shouldn't, and it thankfully it gave me an error, which means I have to find a better way.
Basically my struggle is in understanding how I should structure this entire thing based on two factors:
To allow the second conditional statement in sqlconn.php to be typed
as least often as possible for different "selectyacht" functions
that will come in the future.
To allow the connection instance in sqlconn.php to reside outside the function since it will be used many times for different functions.
Returning data in a different place from where it's being called in viewship.php because the call will be a button press, not the results to be shown.
This is probably very simple, but yet it eludes me.
P.S. Some of this code is a copy/paste from other resources on the internet that I'm trying to merge with my own needs.
sqlconn.php
<?php
$servername = "XXXXXXXX";
$username = "XXXXXXXX";
$password = "XXXXXXXX";
$dbname = "XXXXXXXX";
// Instantiate the connection object
$dbconn = new mysqli($servername, $username, $password, $dbname);
// Check if the connection works or show an error
if ($dbconn->connect_error) {
die("Connection failed: " . $dbconn->connect_error);
}
// Create a query based on the ship's name
function selectyacht($shipname) {
global $sqlstatement;
$sqlstatement = "SELECT * FROM ships WHERE Name=" . "'" . $shipname . "'";
}
// Put the sql statement inside the connection.
// Additional sql statements will be added in the future somehow from other functions
$query = $dbconn->query($sqlstatement);
// Return the data from the ship to be repeated as less as possible for each future function
if ($query->field_count > 0) {
while($data = $query->fetch_assoc()) {
return $data;
}
}
else {
echo "No data found";
}
// Close the connection
$dbconn->close();
?>
viewship.php
<html>
<body>
<?php include 'sqlconn.php';?>
<!-- ship being selected from different buttons -->
<?php selectyacht("Pelorus");?>
<br>
<!-- This is the output result -->
<?php echo $data["Designer"];?>
<?php echo $data["Length"];?>
<?php echo $data["Beam"];?>
<?php echo $data["Height"];?>
</body>
</html>
Mate, I am not sure if I can cover whole PHP coding standards in one answer but I will try to at least direct you.
First of all you need to learn about classes and object oriented programming. The subject itself could be a book but what you should research is autoloading which basically allows you to put your functions code in different files and let server to include these files when you call function used in one of these files. This way you will be able to split code responsible for database connection and for performing data operations (fetching/updating/deleting).
Second, drop mysqli and move to PDO (or even better to DBAL when you discover what Composer is). I know that Internet is full of examples based on mysqli but this method is just on it's way out and it is not coming back.
Next, use prepared statements - it's a security thing (read about SQL injection). Never, ever put external variables into query like this:
"SELECT * FROM ships WHERE Name=" . "'" . $shipname . "'";
Anyone with mean intentions is able to put there string which will modify your query to do whatever he wants eg. erase your database completely. Using prepared statements in PDO your query would look like this:
$stmt = $this->pdo->prepare("SELECT * FROM ships WHERE Name = :ship_name");
$stmt->bindValue(':ship_name', $shipname);
Now to your structure - you should have DB class responsible only for database connection and Ships class where you would have your functions responsible eg. for fetching data. Than you would pass (inject) database connection as an argument to class containing you selectYacht function.
Look here for details how implementation looks like: Singleton alternative for PHP PDO
For
'Returning data in a different place from where it's being called'
If I understand you correctly you would like to have some field to input ship name and button to show its details after clicking into it. You have 2 options here:
standard form - you just create standard html form and submit it with button click redirecting it to itself (or other page). In file where you would like to show results you just use function selectYacht getting ship name from POST and passing it to function selectYacht and then just printing it's results (field by field in places you need them)
AJAX form - if you prefer doing it without reloading original page - sending field value representing ship name via AJAX to other page where you use selectYacht function and update page with Java Script
I had asked a similar question a few days ago but think I was trying to do to much at one time. I am hoping someone can help get me started on this.
I have two drop down lists, one will be populated with years (2012, 2011 etc) and I have some mySQL databases called "db_2012", "db_2011" etc. In these databases are tables representing months.
I would like the user to select a year and then use that selection to query the correct db and return a list of table names which will be used to populate the second drop down list. Then click a button "See Results" to query the selected table and show the results.
I am putting this on a wordpress website and am using a php template file that I created. This is still new to me and what I have so far doesnt work like I want it too, it is basically setup now that you select a year and select a month (not populated from db) and click a button. It makes the query and my table is displayed, but I need this solution to be more dynamic and work as described above. Thanks for the help.
echo '<form action="" method="post">';
echo'<select name="years" id="years">';
foreach($yearList as $year){
echo'<option value="'.$year.'">'.$year.'</option>';
}
echo'</select><br />';
echo '<select name="monthList" id="months">';
foreach($monthList as $month) {
echo'<option value="'.$month.'">'.$month.'</option>';
}
echo '</select>';
echo '<input type=\'submit\' value=\'See Results\'>';
echo '</form'>
$yearList and $monthList are just pre populated arrays. So now from here I want to click the See Results button and query my sql database using the parameters from the drop down selections.
$database = $_POST['yearList'];
$month = $_POST['monthList'];
$wpdbtest_otherdb = new wpdb('Username', 'Password', $database, 'localhost');
$qStr = "SELECT * FROM $month";
$myResults = $wpdbtest_otherdb->get_results($qStr, OBJECT);
It sounds like you want to send an AJAX call to a separate php page for security and processing, then have the PHP return XML that you parse back into the second selection box via the AJAX callback. It can be a little messy, but it allows you to check for weird form values that users might inject.
Edit: The PHP will receive your AJAX parameters as parts of the $_GET or the $_POST array. From there, you can do your checks and db call (or not), then add header("Content-Type:text/xml"); so the server sends it back with the correct header. After that you'll need to echo the XML-formatted data you want the JavaScript to receive. Just remember not to echo anything other than the XML if the request is supposed to go through.
After spending 3 days on internet and struggling with so many different forums , i have found a match and similar case of my problem here.
Friends, I am zero in PHP, but still i have managed to do something to fulfill my requirement.
I am stuck with one thing now..So i need help on....
I am using one html+php form to submit database into mysql.
I created a display of that table through php script on a webpage.
Now i want a datepicker option on that displayed page by which i should able to select the date range and display the data of that date range from my mysql table.
And then take a export of data displayed of selected date range in excel.
This displayed page is login protected, so i want after login the next thing comes in should show a sate selection option which should be fromdate to to date , and then records should displayed from the database and i can take export of those displayed results in excel file.
The code i am using on this page is below which do not have any thing included for excel export and date picker script, I am pasting the code here and request you to please include the required code in it as required.
Thanks In advance
<?php
//database connections
$db_host = 'localhost';
$db_user = '***********';
$db_pwd = '*************';
$database = 'qserves1_uksurvey';
$table = 'forms';
$file = 'export';
if (!mysql_connect($db_host, $db_user, $db_pwd))
die("Can't connect to database");
if (!mysql_select_db($database))
die("Can't select database");
// sending query
$result = mysql_query("SELECT * FROM {$table} ORDER BY date desc");
if (!$result) {
die("Query to show fields from table failed");
}
$num_rows = mysql_num_rows($result);
$fields_num = mysql_num_fields($result);
echo "$num_rows";
echo "<h1></h1>";
echo "<table border='1'><tr>";
// printing table headers
for($i=0; $i<$fields_num; $i++)
{
$field = mysql_fetch_field($result);
echo "<td>{$field->name}</td>";
}
echo "</tr>\n";
// printing table rows
while($row = mysql_fetch_row($result))
{
echo "<tr>";
// $row is array... foreach( .. ) puts every element
// of $row to $cell variable
foreach($row as $cell)
echo "<td>$cell</td>";
echo "</tr>\n";
}
mysql_free_result($result);
?>
</body></html>
This isn't a "write my code for me, please" site, so you're going to need to be a little more engaging and pro-acive. But we can certainly provide some guidance. Let's see...
Currently you have a page which displays all records from a given table, is that correct? And you need to do two things:
Before displaying any records, have the user select a date range. And keep the date range selection on the page so the user can re-select.
Provide a button which lets the user export the selected records to Excel.
For either of these, you're going to need to add an actual form to the page. Currently there isn't one. For the date picker, I recommend (naturally) using the jQuery UI datepicker. So the form for that would look something like this:
<form method="POST" action="myPHPFile.php">
<input type="text" id="fromDate" name="fromDate" />
<input type="text" id="toDate" name="toDate" />
<input type="submit" name="filterDate" value="Submit" />
</form>
<script>
$(function() {
$("#fromDate").datepicker();
$("#toDate").datepicker();
});
</script>
You may have to wrap the JavaScript in a $(document).ready(){} in order to make it work correctly, you'll want to test that. Anyway, this will give you a form to submit the dates to your script. Wrap the parts of your script which output data in a conditional which determines if the form values are present or not. If they're not, don't fetch any records. If they are, do some basic input checking (make sure the values are valid values, make sure fromDate is before toDate, etc.) and construct your SQL query to filter by date range. (Do take care to avoid SQL injection vulnerabilities here.)
For the Excel output, you may be able to find a ready-made solution for you that just needs a little tinkering. If I were to create one from scratch, I'd probably just output to a .csv file rather than a full Excel file. Most users don't know/care the difference. In that case, you'd just want to either create a second script which is nearly identical to the existing one or add a flag to the existing one which switches between HTML and CSV output, such as via a hidden form field.
For the output of the CSV, first make sure you set your response headers. You'll want to write a header to tell the browser that you're outputting a CSV file rather than text/html, and possibly suggest a file name for the browser to save. Then, the form inputs the SQL query will all be pretty much the same as before. The only difference is in the "HTML" that's being output. Rather than HTML tags, you'd wrap the records in commas, double-quotes (where appropriate), and carriage returns.
There's really nothing special to outputting a "file" vs. "HTML" because the HTTP protocol has no distinction between the two. It's always just text with headers.
Now, I'm sure you have more questions regarding this. And that's fine. In fact, we like to encourage asking (and, of course, answering) questions here. So please feel free to ask for clarification either in comments on this answer (or other answers), or by editing and refining your original question, or by asking an entirely new question if you have a specific topic on which you need help. Ideally, a good question on Stack Overflow consists of sample code which you are trying to write, an explanation of what the code is supposed to be doing, a description of the actual resulting output of the code, and any helpful information relevant to the code. As it stands right now, your question provides code somewhat unrelated to what you're asking, and you're just requesting that we add some features to it outright for you.