I'm constructing a webpage to submit camera bookings to a MYSQL database. This webpage has a html frontend that forwards it to the following PHP page, which then submits that information to the MYSQL
Currently the client wishes for there to be no way of making duplicate bookings of the Cameras. To fulfill this, I have constructed the following PHP page, which checks if the chosen camera in the html frontend ($_POST[camera]) is the same as anything in the $result_array array. The code is as follows:
<?php
$con = mysql_connect("****","*****","*******");
if (!$con) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db("****", $con);
$query = "SELECT Camera FROM T_Bookings";
$result = mysql_query($query) or die ("no query");
$result_array = array();
while($row = mysql_fetch_array($result)) {
$result_array[] = $row;
}
$fixed_array = array_keys($result_array);
if (in_array($_POST[camera],$result_array)){
$x = 1;
$y = 2;
}
if($x + $y == 3){
echo "Camera already booked!";
}
else {
mysql_query("INSERT INTO T_Bookings (F_Name, L_Name, Camera, Bag, Cable, Tripod, MemoryCard, Date, Authorised)
VALUES ('$_POST[firstname]','$_POST[lastname]','$_POST[camera]','$_POST[bag]','$_POST[cable]','$_POST[tripod]','$_POST[memory]','$_POST[date]',)");
echo "1 record added";
if (!mysql_query($sql,$con)) {
die('Error: ' . mysql_error());
}
}
mysql_close($con);
?>
However, it is consistently placing a booking even if these conditions aren't met. Why is this the case?
Thanks,
Dayne.
mysql_fetch_array($result) returns an array like
array('Camera' => 'Whatever')
So change the line below to read
$result_array[] = $row['Camera'];
There's a fundamental flaw in your logic. You have a requirement for a unique value and the current implementation does not provide any such guarantee (learn about ACID on Wikipedia: http://en.m.wikipedia.org/wiki/ACID).
You're in luck though. MySQL happens to provide just what you need with little effort. Create a unique index on the Camera column (http://dev.mysql.com/doc/refman/5.5/en/create-index.html). Then don't check for a previous entry with the same name. Simply try to do an insert. MySQL will return an error which is easily handled and your code just became simpler, easier to read and manage.
Related
I am trying to sort a single table (of 10k+ rows) into two separate tables, but seem to be running into a nonsense error that I can't figure out. When i comment out the mysqli insert statements, the variables are printing out correctly and updating as they should. I can see all of the data with the correct keys and values even when looping through all the values in the table.
When I add in the insert statement and place it in a mysqli_query, however, I am suddenly getting tons of mysqli errors saying that there are suddenly duplicate primary keys, but as per the previous tests, there are no duplicates. Other times, it seems to only loop once and then stop (or loop the correct amount of times, but doing nothing each time. I have printed out the mysql statements and was able to see that they were all correct before attempting the query, and yet it still causes issues when actually running. The code in its entirety is included below, but I cannot figure out what the issue is for the life of me.
$sql = "SELECT * FROM originalTable ORDER BY port LIMIT 20";
$result = mysqli_query($conn, $sql);
$num_Rows = mysqli_num_rows($result);
echo $num_Rows."<br/>";
// gets data for each row in the table
for($i=0; $i<$num_Rows; $i++){
$row = mysqli_fetch_assoc($result);
$ID = $row["ID"];
echo $ID."<br/>";
$IP = $row["IP"];
echo $IP."<br/>";
$port = $row["port"];
echo $port."<br/>";
$running = $row["running"];
echo $running."<br/>";
$afk = $row["afk"];
echo $afk."<br/>";
$gamemode = $row["gamemode"];
echo $gamemode."<br/>";
$maxplayers = $row["maxplayers"];
echo $maxplayers."<br/>";
$spawnprotection = $row["spawnprotection"];
echo $spawnprotection."<br/>";
$whitelist = $row["whitelist"];
echo $whitelist."<br/>";
$enablequery = $row["enablequery"];
echo $enablequery."<br/>";
$enablercon = $row["enablercon"];
echo $enablercon."<br/>";
$rconpassword = $row["rconpassword"];
echo $rconpassword."<br/>";
$motd = $row["motd"];
echo $motd."<br/>";
$announceachieve = $row["announceplayerachievements"];
$allowflight = $row["allowflight"];
$spawnanimals = $row["spawnanimals"];
$spawnmobs = $row["spawnmobs"];
$forcegamemode = $row["forcegamemode"];
$hardcore = $row["hardcore"];
$pvp = $row["pvp"];
$difficulty = $row["difficulty"];
$generatorsettings = $row["generatorsettings"];
$levelname = $row["levelname"];
$levelseed = $row["levelseed"];
$leveltype = $row["leveltype"];
$autosave = $row["autosave"];
if($IP == $server1){
$server = "server1table";
$sql1 = "INSERT INTO server1table (id, ip, port, running, afk, gamemode, maxplayers, spawnprotection,
whitelist, enablequery, enablercon, rconpassword, motd, announceplayerachievements,
allowflight, spawnanimals, spawnmobs, forcegamemode, hardcore, pvp, difficulty,
generatorsettings, levelname, levelseed, leveltype, autosave) VALUES ('$ID', '$IP',
'$port', '$running', '$afk', '$gamemode', '$maxplayers', '$spawnprotection', '$whitelist',
'$enablequery', '$enablercon', '$rconpassword', '$motd', '$announceachieve', '$allowflight', '$spawnanimals',
'$spawnmobs', '$forcegamemode', '$hardcore', '$pvp', '$difficulty', '$generatorsettings', '$levelname',
'$levelseed', '$leveltype', '$autosave')";
echo $sql1;
$result = mysqli_query($conn, $sql1);
echo "Server 1<br/>";
if($result){
echo "Success?";
}
else{
echo "Failure = " . $conn->error;
}
} else if ($IP == $Server2){
$server = "server2table";
$sql2 = "INSERT INTO server2table (id, ip, port, running, afk, gamemode, maxplayers, spawnprotection,
whitelist, enablequery, enablercon, rconpassword, motd, announceplayerachievements,
allowflight, spawnanimals, spawnmobs, forcegamemode, hardcore, pvp, difficulty,
generatorsettings, levelname, levelseed, leveltype, autosave) VALUES ('$ID', '$IP',
'$port', '$running', '$afk', '$gamemode', '$maxplayers', '$spawnprotection', '$whitelist',
'$enablequery', '$enablercon', '$rconpassword', '$motd', '$announceachieve', '$allowflight', '$spawnanimals',
'$spawnmobs', '$forcegamemode', '$hardcore', '$pvp', '$difficulty', '$generatorsettings', '$levelname',
'$levelseed', '$leveltype', '$autosave')";
echo $sql2;
$result = mysqli_query($conn, $sql2);
echo "Server 2<br/>";
if($result){
echo "Success?";
}
else{
echo "Failure = " . $conn->error;
}
}
EDIT: The ID in the table above is not the table ID field or primary key. It represents the ID of the player. The port is the primary key of the table
Clarification: In one iteration of this code, it sent everything to server 1 with no issues, but it totally ignored server 2. I have since tested and ensured that the split (if statement) worked as intended, and it prints the correct server name and sets $sql to the intended value (as it prints out). It will only move the first column of the table and then it sets everything else to blank and the ID to 0 and sends a bunch of duplicate primary errors.
I don't think you should be inserting the IDs, that might be where you're fighting with possibly the table primary keys and auto_increment. Just remove the id from the insert and it should be fine. Depending upon how you've set up the table structure. Generally you shouldn't need to preserve the IDs, that's just there for uniqueness and indexing housekeeping etc.
I'm currently building a small site to retrieve player stats for a computer game from a mysql db and display them online.
I get player statistics for a list of players from a third party API and am trying to insert them into a table in the db. However my code is performing the inserts twice - the primary key restriction on the table stops duplicate entries, but I don't want to accept this.
Something is amiss with my looping logic, but I'm going in my own loop trying to figure this one out.
Sequence of events is:
I query my db to get the player ID's needed for the API calls
I put these in an array
I query the third party api in a loop to get all the player stats
I want to insert the stats (1 row per player) to my db (I plan to escape the strings etc, it's a work in progress)
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$member_data[] = $row;
}
foreach ($member_data as $id) {
$endpoint = "http://www.bungie.net/Platform/Destiny/Stats/2/".$id[destiny_membership_id]."/".$id[destiny_character_id]."/";
$bungie_result = hitBungie($endpoint);
$response = json_decode($bungie_result, true);
$destiny_membership_id = $id[destiny_membership_id];
$destiny_character_id = $id[destiny_character_id];
$kills_deaths_ratio = $response[Response][allPvP][allTime][killsDeathsRatio][basic][displayValue];
// DB insert
$sql = "INSERT INTO xax_pvp_stats (destiny_membership_id,destiny_character_id,kills_deaths_ratio) ";
$sql .= "VALUES ('$destiny_membership_id','$destiny_character_id','$kills_deaths_ratio') ";
$result = $conn->query($sql);
if ($conn->query($sql) === FALSE) {
echo "<br />Error: " . $sql . "<br />" . $conn->error;
} else {
echo $destiny_character_id." is in the DB";
}
}
} else {
echo "0 results";
}
You're executing the query twice. Once here:
$result = $conn->query($sql);
and once here:
if ($conn->query($sql) === FALSE) {
I'm guessing you meant to examine the result in the second line:
if ($result === FALSE) {
Several issues, starting with the one you're worried about (insert happening twice):
1) You're calling $conn->query twice, which, of course, executes the INSERT query twice:
Here:
$result = $conn->query($sql);//insert1
if ($conn->query($sql) === FALSE) {//insert 2
echo "<br />Error: " . $sql . "<br />" . $conn->error;
} else {
echo $destiny_character_id." is in the DB";
}
2) Your code is vulnerable to injection, learn about prepared statements and use them
3) accessing values in an associative array requires the keys to be quoted: $response[Response][allPvP][allTime][killsDeathsRatio][basic][displayValue] issues notices. When developing, always use display_errors, and set the error level as strict as you can E_STRICT|E_ALL is recommended.
You're running the query twice: once when you set $result then again in the following if statement. Remove the $result line (you're not using that variable anyway) and you'll be good to go.
Im trying to sum up all the values in this data base but for some reason i cant do i, I looked all over stack overflow and tried multiple methods but none seem to work. My current code is
<?php
error_reporting(0);
//INCLUDES//
include 'config.php';
//INCLUDES//
//DATA FETCH//
$rank=$_POST['R'];
$drank=$_POST['DR'];
//DATA FETCH//
//MYSQL STUFF//
$con=mysqli_connect($ip,$login,$password,$dbname);
for ($i = $rank; $i <= $drank; $i++) { // LOOP UNTIL 20 IS MET
$s=mysqli_query($con, "SELECT sum(rankprice) FROM cost WHERE rank='$i'");
if($s === FALSE) { //CHECK IF DATA IS THERE
die('Error: ' . mysqli_error($con)); // IF NOT THERE SEND ERROR
}
$row = mysqli_fetch_array($s); //PUT DATA IN ROW
echo $row[0];
}
?>
It connects to the database no problem. When I use echo $row[0]; it prints all the values of the column in order. Ive tried putting it into an array and printing it but it seems that doesnt work either. The only way it seems to work is when I add ALL the values in the column by removing WHERE rank='$i' in the SQL code which I dont want to do. Please help !
Try the following query :
$rankarr = array();
for ($i = $rank; $i <= $drank; $i++) { // LOOP UNTIL 20 IS MET
$rankarr[] = $i;
}
$rankarr = implode(',', $rankarr);
$s=mysqli_query($con, "SELECT sum(rankprice) As myrank FROM cost WHERE rank in ($rankarr)");
if($s === FALSE) { //CHECK IF DATA IS THERE
die('Error: ' . mysqli_error($con)); // IF NOT THERE SEND ERROR
}
$row = mysqli_fetch_array($s); //PUT DATA IN ROW
You now want to get the sum value of rankprice in one same rank. So the result of sum() will differ from the rank in one sql. You should tell mysql by adding group by clause, which group the table by rank and get the sum() of each group.
$s=mysqli_query($con, "SELECT sum(rankprice) FROM cost WHERE rank='$i' GROUP BY rank ");
I hope my title isn't completely confusing. I'd like to start by saying I am in now way a programmer and am an amateur with PHP and MySQL, which I use for online gaming. I have been tirelessly working at this for a few days, with no success. I've been toying with the idea of asking for help here, hoping folks go easy on me and don't completely rip apart my code! Like I said, I'm an amateur.
Basically, what I'm trying to do is match the $horsename data from my $_POST array with name in my table called horses. If they do not match it will add a horse with that name into the horses table. If they do match, it will simply continue on and add the data from the $_POST array into the results table for each line.
The issue I'm getting, (and I've toyed with this multiple times, with a different issue arising each time) is even if the $horsename matches name in the horses table, it tries to add a new horse into the horses table. It also is not moving onto the next line of data and will try to add the same horse over and over again. (Hope that makes sense!)
I'm pasting most of my code from this page below, just in case it's something earlier in my code causing this issue. Please note, a portion of this code is not my own and I am working on it for someone else, so if things are not completely uniform in a couple of spots, that is why. The portion I'm working on is what I've mentioned above.
function stripslashes_deep($value) {
$value = is_array($value) ?
array_map('stripslashes_deep', $value) :
stripslashes($value);
return $value;
}
$results = str_replace("\r", '', trim($_POST['news']));
$data = array();
$lines = explode("\n", $results);
foreach ($lines as $place) {
if (!empty($place)) {
$data = array();
$detail = explode(",", $place);
if (!empty($detail)) {
$id = '';
$show = $_POST['show'];
$year = $_POST['year'];
$association = $_POST['association'];
$chpoints = $_POST['chpoints'];
$rchpoints = $_POST['rchpoints'];
$ttpoints = $_POST['ttpoints'];
$chearnings = $_POST['chearnings'];
$rchearnings = $_POST['rchearnings'];
$ttearnings = $_POST['ttearnings'];
$horsename = stripslashes(trim($detail[0]));
$placement = stripslashes(trim($detail[1]));
$class = stripslashes(trim($detail[2]));
if($placement === 'CH'){
$points = $chpoints;
}
else if ($placement === 'RCH') {
$points = $rchpoints;
}
else {
$points = $ttpoints;
}
if ($placement === 'CH') {
$earnings = $chearnings;
}
else if ($placement === 'RCH') {
$earnings = $rchearnings;
}
else {
$earnings = $ttearnings;
}
$horses = mysql_query("SELECT name FROM horses") or die ('Error accessing database: ' . mysql_error());;
while($row = mysql_fetch_array($horses)) {
$storedname = addslashes(trim($row['name']));
if ($storedname == $horsename) {
echo "The names do match for $horsename";
}
else {
echo "The names do not match for $horsename";
$addhorse="INSERT INTO horses (id, owned_by, name, yob, color, breed, discipline, sire, dam, damsire, bred_by, gender)
VALUES ('','25','$horsename','','','','','','','','','')";
mysql_query($addhorse) or die ('Error updating database: ' . mysql_error());
echo 'Added '. $horsename .' to Archive.';
}
}
if (isset($_POST['news'])) {
$query="INSERT INTO `results` (`id`, `show`, `year`, `place`, `name`, `class`, `points`)
VALUES ('$id','$show','$year','$placement','$horsename','$class','$points')";
mysql_query($query) or die ('Error updating database: ' . mysql_error());
echo "Result successfully added!" ;
}
};
};
};
To take a snip-it from above, this is the place I'm having the issues:
$horses = mysql_query("SELECT name FROM horses") or die ('Error accessing database: ' . mysql_error());;
while($row = mysql_fetch_array($horses)) {
$storedname = addslashes(trim($row['name']));
if ($storedname == $horsename) {
echo "The names do match for $horsename";
}
else {
echo "The names do not match for $horsename";
$addhorse="INSERT INTO horses (id, owned_by, name, yob, color, breed, discipline, sire, dam, damsire, bred_by, gender)
VALUES ('','25','$horsename','','','','','','','','','')";
mysql_query($addhorse) or die ('Error updating database: ' . mysql_error());
echo 'Added '. $horsename .' to Archive.';
}
}
If anything from the page where news is coming from is needed, please let me know.
Thanks in advance!
The problem is that you are querying the database for a list of every horse name. You're iterating through that list and each time the names don't match, you're inserting the new name. What you need to do instead is to query for the specific name.
SELECT * FROM horses WHERE name = '$horsename'
If this returns a row, then you know the horse is already in the database. If it returns no rows, then you can safely insert once. By the way, you'll want to properly escape your input to prevent SQL injections so don't use my code verbatim.
Try this:
$horses = mysql_query("SELECT name FROM horses") or die ('Error accessing database: ' . mysql_error());;
$i = 0;
$horsename = "";
while($row = mysql_fetch_array($horses)) {
$storedname = addslashes(trim($row['name']));
if ($storedname == $horsename) {
$i = 1;
}
}
if($i == 1) {
echo "The names do match for $horsename";
}
else {
echo "The names do not match for $horsename";
$addhorse="INSERT INTO horses (id, owned_by, name, yob, color, breed, discipline, sire, dam, damsire, bred_by, gender)
VALUES ('','25','$horsename','','','','','','','','','')";
mysql_query($addhorse) or die ('Error updating database: ' . mysql_error());
echo 'Added '. $horsename .' to Archive.';
}
Long before I knew anything - not that I know much even now - I desgined a web app in php which inserted data in my mysql database after running the values through htmlentities(). I eventually came to my senses and removed this step and stuck it in the output rather than input and went on my merry way.
However I've since had to revisit some of this old data and unfortunately I have an issue, when it's displayed on the screen I'm getting values displayed which are effectively htmlentitied twice.
So, is there a mysql or phpmyadmin way of changing all the older, affected rows back into their relevant characters or will I have to write a script to read each row, decode and update all 17 million rows in 12 tables?
EDIT:
Thanks for the help everyone, I wrote my own answer down below with some code in, it's not pretty but it worked on the test data earlier so barring someone pointing out a glaring error in my code while I'm in bed I'll be running it on a backup DB tomorrow and then on the live one if that works out alright.
I ended up using this, not pretty, but I'm tired, it's 2am and it did its job! (Edit: on test data)
$tables = array('users', 'users_more', 'users_extra', 'forum_posts', 'posts_edits', 'forum_threads', 'orders', 'product_comments', 'products', 'favourites', 'blocked', 'notes');
foreach($tables as $table)
{
$sql = "SELECT * FROM {$table} WHERE data_date_ts < '{$encode_cutoff}'";
$rows = $database->query($sql);
while($row = mysql_fetch_assoc($rows))
{
$new = array();
foreach($row as $key => $data)
{
$new[$key] = $database->escape_value(html_entity_decode($data, ENT_QUOTES, 'UTF-8'));
}
array_shift($new);
$new_string = "";
$i = 0;
foreach($new as $new_key => $new_data)
{
if($i > 0) { $new_string.= ", "; }
$new_string.= $new_key . "='" . $new_data . "'";
$i++;
}
$sql = "UPDATE {$table} SET " . $new_string . " WHERE id='" . $row['id'] . "'";
$database->query($sql);
// plus some code to check that all out
}
}
Since PHP was the method of encoding, you'll want to use it to decode. You can use html_entity_decode to convert them back to their original characters. Gotta loop!
Just be careful not to decode rows that don't need it. Not sure how you'll determine that.
I think writing a php script is good thing to do in this situation. You can use, as Dave said, the html_entity_decode() function to convert your texts back.
Try your script on a table with few entries first. This will make you save a lot of testing time. Of course, remember to backup your table(s) before running the php script.
I'm afraid there is no shorter possibility. The computation for millions of rows remains quite expensive, no matter how you convert the datasets back. So go for a php script... it's the easiest way
This is my bullet proof version. It iterates over all Tables and String columns in a database, determines primary key(s) and performs updates.
It is intended to run the php-file from command line to get progress information.
<?php
$DBC = new mysqli("localhost", "user", "dbpass", "dbname");
$DBC->set_charset("utf8");
$tables = $DBC->query("SHOW FULL TABLES WHERE Table_type='BASE TABLE'");
while($table = $tables->fetch_array()) {
$table = $table[0];
$columns = $DBC->query("DESCRIBE `{$table}`");
$textFields = array();
$primaryKeys = array();
while($column = $columns->fetch_assoc()) {
// check for char, varchar, text, mediumtext and so on
if ($column["Key"] == "PRI") {
$primaryKeys[] = $column['Field'];
} else if (strpos( $column["Type"], "char") !== false || strpos($column["Type"], "text") !== false ) {
$textFields[] = $column['Field'];
}
}
if (!count($primaryKeys)) {
echo "Cannot convert table without primary key: '$table'\n";
continue;
}
foreach ($textFields as $textField) {
$sql = "SELECT `".implode("`,`", $primaryKeys)."`,`$textField` from `$table` WHERE `$textField` like '%&%'";
$candidates = $DBC->query($sql);
$tmp = $DBC->query("SELECT FOUND_ROWS()");
$rowCount = $tmp->fetch_array()[0];
$tmp->free();
echo "Updating $rowCount in $table.$textField\n";
$count=0;
while($candidate = $candidates->fetch_assoc()) {
$oldValue = $candidate[$textField];
$newValue = html_entity_decode($candidate[$textField], ENT_QUOTES | ENT_XML1, 'UTF-8');
if ($oldValue != $newValue) {
$sql = "UPDATE `$table` SET `$textField` = '"
. $DBC->real_escape_string($newValue)
. "' WHERE ";
foreach ($primaryKeys as $pk) {
$sql .= "`$pk` = '" . $DBC->real_escape_string($candidate[$pk]) . "' AND ";
}
$sql .= "1";
$DBC->query($sql);
}
$count++;
echo "$count / $rowCount\r";
}
}
}
?>
cheers
Roland
It's a bit kludgy but I think the mass update is the only way to go...
$Query = "SELECT row_id, html_entitied_column FROM table";
$result = mysql_query($Query, $connection);
while($row = mysql_fetch_array($result)){
$updatedValue = html_entity_decode($row['html_entitied_column']);
$Query = "UPDATE table SET html_entitied_column = '" . $updatedValue . "' ";
$Query .= "WHERE row_id = " . $row['row_id'];
mysql_query($Query, $connection);
}
This is simplified, no error handling etc.
Not sure what the processing time would be on millions of rows so you might need to break it up into chunks to avoid script timeouts.
I had the exact same problem. Since I had multiple clients running the application in production, I wanted to avoid running a PHP script to clean the database for every one of them.
I came up with a solution that is far from perfect, but does the job painlessly.
Track all the spots in your code where you use htmlentities() before inserting data, and remove that.
Change your "display data as HTML" method to something like this :
return html_entity_decode(htmlentities($chaine, ENT_NOQUOTES), ENT_NOQUOTES);
The undo-redo process is kind of ridiculous, but it does the job. And your database will slowly clean itself everytime users update the incorrect data.