PHP - Reducing an independent record stock value by 1 - php

I'm currently doing a school project and I'm using dreamweaver along with a backend database using phpMyAdmin.
Now, what i need to do is, when I click the button, it will reduce the stock column value in the "products" table by 1.
However there are different products in the table. Shown below:
http://i.stack.imgur.com/vLZXQ.png
So lets say, A user is on the game page for "Destiny" and clicks on the Buy now button, how can i make it reduce the stock level by one, but only for the Destiny record and not for the Fifa 15 column. So Destiny stock becomes 49, but Fifa stays 50. Will i just need to make each button have a different script or?
Currently, I made a button in the page, which links to an action script, but im not sure what sort of code i will be using.
Thank you

xNeyte is giving you some good advice, but it comes across to me that you - Xrin - are completely new to programming database contents with PHP or similar?
So some step by steps:
MYSQL databases should be connected with one of two types of connection - PDO and MySQLi_ . MySQL databases will also always work using the native MySQL but as xNeyte already mentioned - this is deprecated and highly discouraged .
So what you have is you pass your information to the PHP page, so your list of games is on index.php and your working page that will update the number of games ordered would be update.php, in this example.
The Index.php file passes via anchor link and $_GET values (although I highly recommend using a php FORM and $_POST as a better alternative), to the update.php page, which needs to do the following things (in roughly this order) to work:
Update.php
Load a valid database login connection so that the page can communicate with the database
Take the values passed from the original page and check that they are valid.
establish a connection with the database and adjust the values as required.
establish the update above worked and then give the user some feedback
So, step by step we'll go through these parts:
I am going to be a pain and use MySQLi rather than PDO - xNeyte used PDO syntax in his answer to you and that is fully correct and various better than MySQLi, for the sake of clarity and your knowledge of MySQL native, it may be easier to see/understand what's going on with MySQLi.
Part 1:
Connection to the database.
This should be done with Object Orientated - Classes,
class database {
private $dbUser = "";
private $dbPass = ""; //populate these with your values
private $dbName = "";
public $dbLink;
public function __construct() {
$this->dbLink = new mysqli("localhost", $this->dbUser, $this->dbPass, $this->dbName);
}
if (mysqli_connect_errno()) {
exit('Connect failed: '. mysqli_connect_error());
}
if ( ! $this->dbLink )
{
die("Connection Error (" . mysqli_connect_errno() . ") "
. mysqli_connect_error());
mysqli_close($this->dbLink);
}
else
{
$this->dbLink->set_charset("UTF-8");
}
return true;
} //end __construct
} //end class
The whole of the above code block should be in the database.php referenced by xNeyte - this is the class that you call to interact with the database.
So using the above code in the database.php object, you need to call the database object at the top of your code, and then you need to generate an instance of your class:
include "database.php"; ////include file
$dataBase = new database(); ///create new instance of class.
Now When you write $dataBase->dbLink this is a connection to the database. If you do not know your database connection use the details PHPMyAdmin uses, it carries out its tasks in exactly the same way.
Sooo
Part 2:
That is that your database connection is established - now you need to run the update: First off you need to check that the value given is valid:
if (is_numeric($_GET['id']) && $_GET['id'] >0 ){
$id = (int)$_GET['id'];
}
This is simple code to check the value passed from the link is a integer number. Never trust user input.
It is also a good idea never to directly plug in GET and POST values into your SQL statements. Hence I've copied the value across to $id
Part 3:
$sql = "UPDATE <TABLE> SET STOCK = STOCK-1 WHERE Product_ID = ? LIMIT 1";
The table name is your table name, the LIMIT 1 simply ensures this only works on one row, so it will not effect too many stocked games.
That above is the SQL but how to make that work in PHP:
first off, the statement needs to be prepared, then once prepared, the value(s) are plugged into the ? parts (this is MySQLi syntax, PDO has the more useful :name syntax).
So:
include "database.php"; ////include file
$dataBase = new database(); ///create new instance of class.
if (is_numeric($_GET['id']) && $_GET['id'] >0 ){
$id = (int)$_GET['id'];
$sql = "UPDATE <TABLE> SET STOCK = STOCK-1 WHERE Product_id = ? LIMIT 1";
$update = $dataBase->dbLink->prepare($sql);
$update->bind_param("i",$id);
$update->execute();
$counter = $update->affected_rows;
$update->close();
//////gap for later work, see below:
}
else
{
print "Sorry nothing to update";
}
There's probably quite a lot going on here, first off the bind_param method sets the values to plug into the SQL query, replacing the ? with the value of $id. The i indicates it is meant to be an Integer value. Please see http://php.net/manual/en/mysqli-stmt.bind-param.php
The $counter value simply gets a return of the number of affected rows and then something like this can be inserted:
if ($counter > 0 ){
print "Thank you for your order. Stock has been reduced accordingly.";
}
else {
print "Sorry we could not stock your order.";
}
Part 4
And finally if you wish you can then just output the print messages or I tend to put the messages into a SESSION, and then redirect the PHP page back.
I hope this has helped a bit. I would highly recommend if you're not used to the database interactions in this way then either use PDO or MySQLi but do not combine the two, that will cause all sorts of syntax faults. Using MySQLi means that everything you know MySQL can do, is done better with the addition of the letter "i" in the function call. It is also very good for referencing the PHP.net Manual which has an excellent clear detailed examples of how to use each PHP function.

The best is to set a link on each button with the ID of your game (1 for destiny, 2 for Fifa15).
Then your script which the user will launch by clicking will be :
<?php
include('database.php'); // your database connection
if($_GET['id']) {
$id=$_GET['id'];
} else throw new Exception('Invalid parameter');
$statement = myPDO::getInstance->prepare(<<<SQL
UPDATE TABLE
SET STOCK = STOCK-1
WHERE Product_id = :id
SQL
);
$statement->execute(array(":id" => $id));
This script will do the job

Related

Best way to approach sending external php a variable

I was wondering if some one could direct me on the right path to take because every way I have tried has failed or really broken my code. To keep it simple I have page with a dynamically created select box populated with peoples names from a mySQL database its element id is 'insert'. This page also holds the php query
my query on the database works if I hard code a name in but I want to pass it as a variable from the select box. I can't seem to get it to post my variable and return me an id.
heres my query
<?php
function getElementById($id) {
$xpath = new DOMXPath(NEW domDocument);
return $xpath - > query("//*[#id='$id']") - > item(0);
}
$insertName = getElementById('insert');
printf($insertName);
$con = mysqli_connect("localhost", "root", "", "karaoke");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: ".mysqli_connect_error();
}
$sql = "Select id FROM queue where singer = '$insertName'";
$result = mysqli_query($con, $sql) or die("Bad SQL: $sql");
while ($row = mysqli_fetch_assoc($result)) {
$insertAt = ("{$row['id']}");
printf($insertName);
printf($insertAt);
};
?>
whats the best way to get my variable sent to the script and then return me the answer.
thanks
You can use either the POST or GET form methods to send data from your HTML form to your PHP script. In the form element, you will want to set the action to your PHP script like so: <form action = 'your_php_file.php' method = 'GET or POST'>. This means that when the form is submitted, you can get the data from this PHP file. Then, in your PHP, you will want to use the global variable for either POST or GET (depending on which you have used for the form method) to get the value from the select box. Using this method means you can replace your GetById function and assign the value from the form to the $insertName variable using the superglobals.
Another problem in your code is that you use your PHP variables in your SQL query. This means that your code is open to an SQL injection which could lead to problems such as people getting all of the database info (which is bad for a database storing poorly encrypted/hashed passwords, or even storing them in plain text)or could even lead to your database being deleted. To avoid this, you should use prepared statements and parameters whereby the statement is sent first without the variable and the variable is bound after.
Also, take a look at the links above about POST and GET and also about the PHP global variables which will allow you to get the data from your HTML form. Also, here are some links which explain prepared statements and parameters so that you can write more secure PHP code:
Mysqli prepare statement used to prepare the statement. The use of question marks are as placeholders as you later bind your variables to the query.
Mysqli Bind Param used to add in the variable to the SQL statement after the statement has been prepared which prevents SQL injection.
That's all for now, but be sure to ask any questions you may have and I will try my best to answer them all.
EDIT
ADDED CODE - hopefully will demonstrate what you were after, there are some small changes that may need to be made. There may be some extra code needed to fit in with any other code you have, but this should demonstrate the principle of POST and prepared statements with parameters. Written in OOP as opposed to your procedural as I find it cleaner and easier (personal opinion). If there are any problems integrating this be sure to tell me about any errors or issues/further questions. I too am fairly new to PHP.
<?php
$insertName = $_POST['insert']; // Get the value of the select box which will need to have the attribute 'name = "insert"' by POST
printf($insertName);
$con = new mysqli("localhost", "root", "", "karaoke");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: ".mysqli_connect_error();
}
$sql = "Select id FROM queue where singer = ?";
$stmt = $con->prepare($sql);
$stmt->bind_param("s", $insertName); //Binds the string insertName to the question mark in the query
$stmt->execute();
while ($row = $stmt->fetch_assoc()) { // Left as was because syntax is different from PDO which I use. Therefore, I am assuming this part is correct.
$insertAt = ("{$row['id']}");
printf($insertName);
printf($insertAt);
};
?>

update two table in single query

i have two table in sql the 1st table is for account while the 2nd table is for testimonial . i am trying to update the two tables in single query. The update is successful if the account already have a testimonial but fails to update if the account has no testimonial yet .How can i fix this heres my code for the update ....
if(!$update=mysql_query(
"UPDATE
tblapplicant,
tbltestimonial
SET
tblapplicant.ImagePath='".$name."',
tbltestimonial.pic = '".$name."'
WHERE
tblapplicant.appid=tbltestimonial.appid"
)
)
1) You're working with a database, it defeats the purpose to use the same data being inserted into two different tables.
2) One gentleman also mentioned stop using MySQL... heres some reference code for you. Assuming you're using php.
3) If you want to use a single query to update 2 tables with the same info against recommendation. Use a stored procedure to update them both.
4) At which point are these account's interconnected in this query? I'm somehow intrigued if this system is in beta or testing?
With your "Where" conditions without matching a specific record, this will update every record that has a matching ID. This is highly not recommended until you add further conditions like username = .... or a condition that's specific to someone or a specific set of rows.
**I strongly advise you post the tables you're working with and what results you want achieve for the best advise. **
Can't really give a good consultation with you playing the whole overview close to the chest. Using this plain-Jane without further detail on what you're asking for is at your own risk my friend.
include/dbconnect.php optional recommended update
<?php
if (isset($mysqli)){
unset($mysqli);
}
define("HOST", "yo.ur.ip.addr"); // The host you want to connect to.
define("USER", "myfunctionalaccount"); // The database username.
define("PASSWORD", "superdoopersecurepassword!"); // The database password.
define("DATABASE", "thegoods");
$mysqli = new mysqli(HOST, USER, PASSWORD, DATABASE);
if ( $mysqli->connect_error ) {
die('Connect Error: ' . $mysqli->connect_error);
}
?>
functions.php <-- shouldn't be called functions if its going to be your form response
<?php
// SHOULD BE SOME MASSIVE LOGIC UP HERE FOR FORM DATA DECISIONING
include_once "include/dbconnect.php";
$name = addslashes($_FILES['image']['name']);
$image = mysql_real_escape_string(addslashes(file_get_contents($_FILES['image']['tmp_name'])));
if ($stmt = $mysqli->prepare("CALL UpdateTestimonials(?,?,?)"){
$stmt->bind_param($name, $image, $userid);
$stmt->execute();
// optional to show affected rows
$stmt->affected_rows
//
// use if you want to return values from DB
// $stmt->bind_result($result);
// $stmt->fetch;
}
$stmt->close
?>
MySQL build a stored procedure - fyi; definer is optional. Definer will allow you to run a query that only elevated privileges can access due to the safety of such a query. You can use create procedure w/o the definer parameter. dT is just an abbreviation for datatype. You would put varchar or int... etc..
use 'database';
DROP procedure if exists 'UpdateTestimonials';
DELIMITER $$
use 'UpdateTestimonials' $$
CREATE DEFINER='user'#'HOSTNAME/LOCALHOST/%' PROCEDURE 'mynewprocedure' (IN varINPUT varchar, IN varIMG blob, IN varAppID int)
BEGIN
UPDATE tblapplicant
SET imagepath = varINPUT,
pic = LOAD_FILE(varIMG)
WHERE appid = varAppID
END $$
DELIMITER;
Use LEFT JOIN:
if (!$update = mysql_query(
"UPDATE
tblapplicant
LEFT JOIN tbltestimonial ON tblapplicant.appid = tbltestimonial.appid
SET
tblapplicant.ImagePath = '" . $name . "',
tbltestimonial.pic = '" . $name . "'"
)
)
Also, if you need some additional filters for tbltestimonial, add them into LEFT JOIN condition
You could try with a transaction. BTW also please use prepared statements to prevent SQL Injection attacks.
<?php
// prefer mysqli over mysql. It is the more modern library.
$db = new mysqli("example.com", "user", "password", "database");
$db->autocommit(false); // begin a new transaction
// prepare statements
$update_applicant =
$db->prepare("UPDATE tblapplicant
SET tblapplicant.ImagePath = ?"));
$update_applicant->bind_param("s", $name));
$update_applicant->execute();
$update_testimonial =
$db->prepare("UPDATE tbltestimonial
SET tbltestimonial.pic = ?"));
$update_testimonial->bind_param("s", $name))
$update_testimonial->execute();
$db->commit(); // finish the whole transaction as successful,
// when everything has succeeded.
?>
Of course that would not create any testimonials, that don't exist. It just updates those, that do. When you want to insert new entries in tbltestimonial, do so explicitly with an INSERT statement inside the transaction.
MySQL does not fully support transactions. The tables have to use a table type, that can handle them, e.g. innodb. When that is the case, the transaction will make sure, that everyone else either sees all changes from the transactions, or none.
In many cases transactions allow you to perform a group of simple steps, that otherwise would need complex single queries or would not be possible without transactions at all.
Alternative Solution
Another approach of course would be an update-trigger. Create a trigger in your database, that fires whenever e.g. tblapplicant is updated and updates tbltestimonial accordingly. Then you don't have to care about that in your application code.

Php adodb CacheExecute com_exception arguments wrong type

I'm trying to get ADODB caching to work. I have a php script where i define the DB connection.
global $conn;
$conn = new COM ("ADODB.Connection");
$connStr = "PROVIDER-SQLOLEDB;SERVER=;UID=;PWD=;DATABASE=);
$conn->open($connStr);
I left the unnecessary details out of the picture.
Then in some other script i import the connection.php, and then try to make a normal query.
$query = "SELECT * from table where some_id = 21540 and other_id = BOGUS_INFO"
$rs = $GLOBALS['conn']->CacheExecute(60,$query);
This returns Uncaught exception 'com_exception'.. ADODB.Connection Arguments are of the wrong type,are out of acceptable range, or are in conflict with another.
I'm baffled because the next line of code works flawlessly.
$rs = $GLOBALS['conn']->execute($query); //OK!
Any ideeas?
I also tried CacheGetOne but i get the same error.
Could it be from the way i defined this thing below? (it's literally like that in my code)
$GLOBALS['ADODB_CACHE_DIR']=$_SERVER['DOCUMENT_ROOT'].'/../cache/adodb';
Well after alot of hassle, i kinda found an answer by choosing another way of doing things. I downloaded the latest ADODB build. Inserted it in my project, and modified files accordingly:
The connection.php changed to:
require('PATH/adodb.inc.php');
require('PATH/adodb-csvlib.inc.php');//read somewhere that i need this for the caching executes
$GLOBALS['ADODB_CACHE_DIR'] = $_SERVER['DOCUMENT_ROOT'].'/cache/adodb';
global $ADODB_CACHE_DIR; //don't know which one adodb usese really to identify cache directory so for safety - both
$ADODB_CACHE_DIR = $_SERVER['DOCUMENT_ROOT'].'/cache/adodb';
$conn = NewADOConnection('mssqlnative');//i tried first with mssql simple but script terminated execution on execute() attempt.. no error.. no nothing.. no output .. strange
$conn->Connect($myServer, $myUser, $myPass, $myDb);
After that i had to fiddle a bit with the code because,
$rs = $conn->CacheExecute(time,query)
returns Adodbrecordset_array_mssqlnative Object, and not an array, and, in my code i used to display and manipulate values as
while (!$rs->EOF) {
$rs['row']->value;
$rs->MoveNext();
}
and now they should be
$rs->fields['row'];
Another tricky thing was getting the fields array to be associated to the names of the columns in my query, but after a short search i discovered
$GLOBALS['conn']->SetFetchMode(ADODB_FETCH_ASSOC);
and voila! Everything works, even the caching.
It took script execution times with this bare optimisation from 1 sec to 0.1 or even 0.005 sometimes.

Fetch data from second database frequently while connection to first database is always available

I m working on old existing project which uses mysql function for database operation. The existing system connects to the database, say cdcol. The connection to this database is available through site wise.
Now I want to fetch data from another database say crawlerdb, assign fetched data to an array and close connection to this database. The connection to second database is inside a function say GetAccess, and each time the extra data needed, the function is called, data fetched and connection closed to the second database.
All I want is connection to first database should be available every time.
The problem I m facing is. If i don't close connection to second database. Then mysql query used after calling the function GetAccess, still search items from second database, because the connection to second database is active. If I close the connection to second database, still the query doesnot work. Following code explains my situation.
<?php
//$conn1 is permanent connection that is used sitewise.
$conn1=mysql_connect("localhost","root","",true) or die(mysql_error());
mysql_select_db("cdcol",$conn1) or die(mysql_error());
echo "1. Current Database = ".mysql_current_db();//prints cdcol
echo "<Br> Function Returned Value = ".GetAccess();
echo "<Br>2. Current Database = ".mysql_current_db(); //In GetAccess function, which is called above if mysql_close($conn2) is used, the mysql_current_db() returns empty value.
//A FUNCTION TO GET EXTRA DATA FROM SECOND DATABASE
function GetAccess(){
$conn2=mysql_connect("localhost","root","",true) or die(mysql_error());
mysql_select_db("crawlerdb",$conn2) or die(mysql_error());
$test=mysql_query("select * from tbllensinfo",$conn2); //here i have used $conn2 as link identifier
$var= mysql_num_rows($test);
mysql_close($conn2);
return $var;
}
//FUNCTION TO IDENTIFY WHICH DATABASE IS CURRENTLY BEING USED
function mysql_current_db() {
$r = mysql_query("SELECT DATABASE()") or die(mysql_error());
return mysql_result($r,0);
}
$res=mysql_query("select * from cds"); //here link identifier $conn1 is not used, i cant change this code because there are several 100s codes, so not possible to change in all of them. Everything will work if $conn1 is used here though
echo "<br>".mysql_num_rows($res);
?>
NOTE:
The two database are hosted on same server, but database users are different, one of which have no access to other database.
So in short What I need is I need to fetch data from second database frequently while connection to first database is always available.
Any help will highly be appreciable, thanks !
Thanks
Sharmila
The mysql functions, such as mysql_query, all have an optional resource parameter identifying the database connection to use. If you omit this second parameter, the functions use the most recently opened connection. That is, they use the connection resulting from the most recent call to mysql_connect. It's considered the most recent result even if you have closed it already.
(Global variable! Let's party like it's 1999!)
If you're going to use more than one connection with mysql calls in your program, you must specify the resource parameter in all mysql_* calls in your program.
Please consider switching to PDO or mysqli. The PHP people have been trying to get rid of this mysql API for years, partly because of this problem, and mostly because it has serious insecurities.

html button to reset field in mysql database using php

Kinda new to mysql and php
I have a hit counter for each page on my site and a private page that list all pages and hits.
I have a button that will reset all pages to zero and next to each page listing I have a reset button that will reset each page individually. This all was using a text file but now I am swtching to mysql database. I have coded the "RESET ALL" button to work but can not get the individual page buttons to work.
the processing code is:
if($_POST[ind_reset]) {
$ind_reset = $_POST[ind_reset];
mysql_connect("server", "username", "password") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());
$sql = 'UPDATE counters SET Hits =\'0\' WHERE Page = \'$ind_reset\';';
}
and the html form code is a string:
$page_reset = "<form id='Reset' action='counter_update.php' method='post'>
<button type='submit' name='ind_reset' value='$formPage'>RESET</button>
</form>";
Let's start with the first thing:
if($_POST[ind_reset]) {
should be
if($_POST['ind_reset']) {
It works without quotes because PHP is silently correcting your error. If you turned error reporting to E_ALL, you would get to see the error message.
One thing that you need to consider is that you can never trust POST data to be what you think it's supposed to be. Maybe you put in a typo. Maybe a hacker is sending you fake POST data. Whichever it is, it will mess up your code if the wrong thing gets put in that database update. For this reason, instead of simply plugging in that POST value into your database, you should have a checker to make sure that the value is a valid one. When I do things like this, I make an array of possible values and use only those values when updating or inserting into the database. Example:
$pages = array('value_on_page'=>'value_put_in_database',
'xyz'=>'thing_in_database_2');
//the valid things to post are either 'value_on_page' or 'xyz',
//but what goes into the database are the values those keys point to
//e.g. if $_POST['ind_reset'] == 'xyz', $ind_reset will be 'thing_in_database_2'
$key = $_POST['ind_reset'];
if(!isset($pages[$key])) {
//if that posted value isn't a key in the array, it's bad
error_log('Invalid posted page'.$key);
} else {
//this is a valid posted page
$ind_reset = $pages[$key];
//** do the database stuff right here in this spot **//
}
Now, for the reason your posted code doesn't work, you are missing the final, crucial part of doing a database query: the part where you actually run the query.
$conn = mysql_connect("server", "username", "password") or error_log(mysql_error());
mysql_select_db("database") or error_log(mysql_error());
$sql = 'UPDATE counters SET Hits =\'0\' WHERE Page = \'$ind_reset\';';
mysql_query($sql, $conn) or error_log(mysql_error());
I hope you have noted that I replaced "die" with "error_log." If you do error_log(mysql_error(), 1, 'youremail#example.com'), it will email it to you. Otherwise, as with in my examples, it gets put into wherever your system's error log file is. You can then have a nice history of your database errors so that, when you inevitably return to StackOverflow with more questions, you can tell us exactly what's been going on. If you use a file, just make sure to either rotate the error log file's name (I name them according to the day's date) or clear it out regularly, or it can get really, really long.
Using the mysqli code you posted in your comment is a better idea than the mysql_* functions, but you don't quite have it correct. The "bind_param" part sticks your variable into the spot where the question mark is. If your variable is a string, you put "s" first, or if it's an integer, you put "i" first, etc. And make sure you close things once you're done with them.
$db = new mysqli("server", "username", "password", "database");
if(!$db->connect_errno) {
$stmt = $db->prepare("UPDATE counters SET Hits = '0' where Page = ?");
$stmt->bind_param('s',$ind_reset); //assuming $ind_reset is a string
if(!$stmt->execute()) {
error_log($stmt->error);
}
$stmt->close();
} else {
error_log($db->connect_error);
}
$db->close();

Categories