I am trying to optimize the speed that my Local database populates in a Web app that is being developed. Currently, it uses PHP to access the Database and then inserts that data into the local database using Javascript.
Problem is, anything more than a couple entries slows it down and I'm pretty sure it's because it executes an individual SQL query for EVERY row. I've been reading up on transactions (Commits and Rollbacks and what not) and it seems like an answer but I'm not entirely sure how to implement it, or even where.
Here is a sample of one of the functions that loads a particular table.
function ploadcostcodes()
{
$IPAddress = '';
$User = '';
$Password = '';
$Database = '';
$Company = '';
$No='';
$Name='';
ploadSQLConnection($IPAddress,$User,$Password,$Database,$Company);
// This Connects to the actual database where the information comes from.
$Login = 'XXXXXXX';
$conn=mssql_connect($IPAddress,$Login,$Password);
if (!$conn )
{
die( print_r('Unable to connect to server', true));
}
mssql_select_db($Database, $conn);
$indent=" ";
$sql="SELECT Cost_Code_No as No, Description as Name, Unit_of_Measure FROM v_md_allowed_user_cost_codes WHERE Company_No = " . $Company . " and User_No = '" . $User . "'";
$rs=mssql_query($sql);
if (!$rs)
{
exit("No Data Found");
}
while ($row = mssql_fetch_array($rs))
{
$No = addslashes($row['No']);
$Name = addslashes($row['Name']);
$Name = str_replace("'",'`',$Name);
$Unit = addslashes($row['Unit_of_Measure']);
//THIS IS WHERE I SEE THE PROBLEM
echo $indent."exeSQL(\"INSERT INTO Cost_Codes (Cost_Code_No,Name,Unit_of_Measure) VALUES('".$No."','".$Name."','".$Unit."')\",\"Loading Cost Codes...\"); \r\n";
}
mssql_free_result($rs);
mssql_close($conn);
return 0;
}
I don't know what needs the transaction(or even if that's what needs to be done). There is MSSQL to access the data, SQLite to insert it and Javascript that runs PHP code.
I would prepare a query with placeholders, then execute it for each row with the right arguments. Something like this (JS part only, using underscore.js for array helpers):
db.transaction(function(tx) {
var q = 'INSERT INTO Cost_Codes (Cost_Code_No, Name, Unit_Of_Measure) VALUES (?, ?, ?)';
_(rows).each(function(row) {
tx.executeSql(q, [row.code, row.name, row.unit]);
});
});
Edit: a query with placeholders has two main benefits:
It makes it a lot easier for the DB engine to cache and reuse query plans (because you are running the same query a hundred times instead of a hundred different queries once).
It makes escaping data and avoiding SQL injections a lot easier.
Related
I have a web game which through an AJAX request accesses the php file below to save user's score to the database.
How secure is this approach? In what way could someone hack this?
<?php
$db = "db name";//Your database name
$dbu = "db username";//Your database username
$dbp = "db user pass";//Your database users' password
$host = "localhost";//MySQL server - usually localhost
$dblink = mysql_connect($host,$dbu,$dbp);
$seldb = mysql_select_db($db);
if(isset($_GET['name']) && isset($_GET['score']))
{
//Lightly sanitize the GET's to prevent SQL injections and possible XSS attacks
$name = strip_tags(mysql_real_escape_string($_GET['name']));
$score = strip_tags(mysql_real_escape_string($_GET['score']));
$sql = mysql_query("INSERT INTO `$db`.`scores` (`id`,`name`,`score`) VALUES ('','$name','$score');");
if($sql)
{
echo 'Your score was saved. Congrats!';
}
else
{
echo 'There was a problem saving your score. Please try again later.';
}
}
else
{
echo 'Your name or score wasnt passed in the request. Make sure you add ?name=NAME_HERE&score=1337 to the tags.';
}
mysql_close($dblink); //Close off the MySQL connection to save resources.
?>
The code you have written is not at all secure check for XSS, SQL injection namely, also you are using deprecated function to interact with the DB.
If you are thinking of taking this to production, you should have some PHP framework which will ease out most of the things for you, there are so many frameworks out there & fairly easy to implement like in a day or two.
Choose From Here
I have a button in a webapp that allows users to request a specially formatted number. When a user click this button 2 scripts run. The first that is fully functional, looks at a number table finds the largest number and increments it by 1. (This is not the Primary Key) the second script which is partially working gets the current date and runs a SQL query to get which period that date falls in. (Periods in this case not always equaling a full month) I know this script is at least partially working because I can access the $datetoday variable called in that script file. However it is not returning the requested data from the periods table. Anyone that could help me identify what I am doing wrong?
<?php
include 'dbh.inc.php';
$datetoday = date("Ymd");
$sql = "SELECT p_num FROM periods where '$datetoday' BETWEEN p_start AND p_end";
$stmt = mysqli_stmt_init($conn);
if(!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../quote.php?quotes=failed_to_write");
exit();
} else {
mysqli_stmt_execute($stmt);
mysqli_stmt_store_result($stmt);
$result = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_assoc($result);
$pnum = $row;
mysqli_stmt_close($stmt);
}
If it helps any one I published my code to https://github.com/cwilson-vts/Quote-Appliction
So first off, I do not use msqli and never learned it. However, I believe I get the gist of what you want to do. I use PDO because I FEEL that it is easier to use, easier to read and it's also what I learned starting off. It's kinda like Apple vs. Samsung... no one product is exactly wrong or right. And each have their advantages and disadvantages. What I'm about to provide you will be in PDO form so I hope that you will be able to use this. And if you can't then no worries.
I want to first address one major thing that I saw and that is you interlacing variables directly into a mysql statement. This is not considered standard practice and is not safe due to sql injections. For reference, I would like you to read these sites:
http://php.net/manual/en/security.database.sql-injection.php
http://php.net/manual/en/pdo.prepared-statements.php
Next, I'm noticing you're using datetime as a variable name. I advise against this as this is reserved in most programming languages and can be tricky. So instead, I am going to change it something that won't be sensitive to it such as $now = "hello world data";
Also I'm not seeing where you would print the result? Or did you just not include that?
Another thing to consider: is your datetime variable the same format as what you are storing in your db? Because if not, you will return 0 results every time. Also make sure it is the right time zone too. Because that will really screw with you. And I will show you that in the code below too.
So now on to the actual code! I will be providing you with everything from the db connection code to the sql execution.
DB CONNECTION FILE:
<?php
$host = '127.0.0.1';
$user = 'root';
$pw = '';
$db = 'test'; // your db name here (replace 'test' with whatever your db name is)
try {
// this is the variable will call on later in the main file
$conn = new PDO("mysql:host=$host;dbname=$db;", $user, $pw);
} catch (PDOException $e) {
// kills the page and returns mysql error
die("Connection failed: " . $e->getMessage());
}
?>
The data file:
<?php
// calls on the db connection file
require 'dbconfig.php';
// set default date (can be whatever you need compared to your web server's timezone). For this example we will assume the web server is operating on EST.
date_default_timezone('US/Eastern');
$now = date("Ymd");
// check that the $now var is set
if(isset($now)) {
$query = $conn->prepare("SELECT p_num FROM periods WHERE p_start BETWEEN p_start AND :now AND p_end BETWEEN p_end AND :now");
$query->bindValue(':now', $now);
if($query->execute()) {
$data = $query->fetchAll(PDO::FETCH_ASSOC);
print_r($data); // checking that data is successfully being retrieved (only a troubleshooting method...you would remove this once you confirm it works)
} else {
// redirect as needed and print a user message
die("Something went wrong!");
}
$query->closeCursor();
}
?>
Another thing I want to mention is that make sure you follow due process with troubleshooting. If it's not working and I'm not getting any errors, I usually start at the querying level first. I check to make sure my query is executing properly. To do that, I go into my db and execute it manually. If that's working, then I want to check that I am actually receiving a value to the variable I'm declaring. As you can see, I check to make sure the $now variable is set. If it's not, that block of code won't even run. PHP can be rather tricky and finicky about this so make sure you check that. If you aren't sure what the variable is being set too, echo or print it with simply doing echo $now
If you have further questions please let me know. I hope this helps you!
I think I know what I was doing wrong, somebody with more PHP smarts than me will have to say for sure. In my above code I was using mysqli_stmt_store_result I believe that was clearing my variable before I intended. I changed that and reworked my query to be more simple.
<?php
include 'dbh.inc.php';
$datetoday = date("Ymd");
$sql = "SELECT p_num FROM periods WHERE p_start <= $datetoday order by p_num desc limit 1";
$stmt = mysqli_stmt_init($conn);
if(!mysqli_stmt_prepare($stmt, $sql)) {
header("Location: ../quote.php?quotes=failed_to_write");
exit();
} else {
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
while( $row = mysqli_fetch_assoc($result)) {
$pnum = $row['p_num'];
echo $pnum;
}
mysqli_stmt_close($stmt);
}
Thanks to #rhuntington and #nick for trying to help. Sorry I am such an idiot.
I'm trying to build a relatively simple PHP login script to connect to MySQL database running on my home server. I know the connection works as I've gotten some data returned as I would expect. However, I am having trouble getting the full script to work.
Essentially, I'm taking in a username/password from the user, and I first do a lookup to get the user_id from the users table. I then want to use that user_id value to do a comparison from user_pswd table (i'm storing usernames and passwords in separate database tables). At one point, I was able to echo the correct user_id based on the username input. But I haven't been able to get all the issues worked out, as I'm pretty new to PHP and don't really know where to see errors since I load this onto my server from a remote desktop. Can anyone offer some advice/corrections to my code?
The end result is I want to send the user to another page, but the echo "test" is just to see if I can get this much working. Thanks so much for the help!
<?php
ob_start();
$con = new mysqli("localhost","username","password","database");
// check connection
if (mysqli_connect_errno()) {
trigger_error('Database connection failed: ' . $con->connect_error, E_USER_ERROR);
}
$users_name = $_POST['user'];
$users_pass = $_POST['pass'];
$user_esc = $con->real_escape_string($users_name);
$pass_esc = $con->real_escape_string($users_pass);
$query1 = "SELECT user_id FROM users WHERE username = ?;";
if ($result1 = $con->prepare($query1)) {
$result1->bind_param("s",$user_esc);
$result1->execute();
$result1->bind_result($userid);
$result1->fetch();
$query2 = "SELECT user_pswd_id FROM user_pswd WHERE active = 1 AND user_id = ? AND user_pswd = ?;";
if ($result2 = $con->prepare($query2)) {
$result2->bind_param("is",$userid,$pass_esc);
$result2->execute();
$result2->bind_result($userpswd);
$result2->fetch();
echo "test", $userpswd;
$result2->free_result();
$result2->close();
} else {
echo "failed password";
}
$result1->free_result();
$result1->close();
}
$con->close();
ob_end_clean();
?>
First time question, long time reader :)
I am building forms dynamically from Columns in a MYSQL DB. These columns
are created/ deleted etc.. elsewhere on my App. My form runs a query against a
SQL View and pulls in the column names and count of columns. Simple! build the form,
with the HTML inputs built with a PHP for loop, and it echos out the relevant HTML for the new form fields. All very easy so far.
Now i want a user to update these dynamically added fields and have the data added to the relevant columns - same table
as existing columns. So, as the input fields are named the same as the columns, they are posted to a PHP script for processing.
Problem is, while i have the actual field names inserted in to the SQL INSERT query, i cannot figure out how to extract the POST
data from the POST dynamically and add this to the VALUEs section of the query.
Here is my attempt....
The Query works without the variables added to it.
It works like this, first section/ is to retrieve the columns names from earlier created VIEW - as these are identical to POST names from the form. Then output to array and variable for insertion to Query. It looks like the implode function works, in that the relevant column names are correct in the statement, but i fear that my attempt to inject the column names on to the POST variables is not working.
$custq = "SELECT * FROM customProperties";
$result = $database->query($custq);
$num_rows = mysql_numrows($result);
while (list($temp) = mysql_fetch_row($result)) {
$columns[] = $temp;
}
$query = '';
foreach($columns as $key=>$value)
{
if(!empty($columns[$key]))
{
$values .= "'".'$_POST'."['".$value."'], ";
}
}
$q = "INSERT INTO nodes
(deviceName,
deviceInfo,
".implode(", ", $columns).",
nodeDateAdded,
status
)
VALUES
('" . $_POST['deviceName'] . "',
'" . $_POST['deviceInfo'] . "',
".$values."
CURDATE(),
'1'
)";
$result = $database->query($q)
Any help is much appreciated. I will feed back as much as i can. Please note, relativity new to PHP, so if i am all wrong on this, i will be glad for any tips/ advice
Regards
Stephen
If you want to get the values of every POST input without knowing the input names then you can do it this way:
//get all form inputs
foreach($_POST as $name => $value)
{
echo $name . " " . $value . "<br>";
}
If you want to get the value of certain POST inputs where you know the name of the input field then you can do it this way:
if(isset( $_GET["deviceName"]))
{
$deviceName = $_POST["deviceName"];
}
if(isset( $_GET["deviceInfo"]))
{
$deviceInfo = $_POST["deviceInfo"];
}
To connect to a database and insert the info then you have to do something like this:
$host = "localhost";
$dbuser = "username";
$pass = "password";
$datab = "databasename";
//Create DB connection
$con=mysqli_connect($host, $dbuser, $pass,$datab);
if (mysqli_connect_errno($con))
{
echo "ERROR: Failed to connect to the database: " . mysqli_connect_error();
}
else
{
echo "Connected to Database!";
}
//insert into database
mysqli_query($con, "INSERT INTO nodes (deviceName, deviceInfo) VALUES ('$deviceName', '$deviceInfo')");
(Don't forget to add mysql_real_escape_string to the $_POST lines after you get it working.)
This is my code to update a table. My problem is that after submitting a fresh record I'm unable to update the first time (it shows blank), but the second time it works fine.
One more thing: when I remove the include statement then it is working fine on submessage.php there is no any phpcode. [annakata: I have no idea what this means]
$pid = $_GET['id'];
$title = $_POST['title'];
$summary = $_POST['summary'];
$content = $_POST['content'];
$catid = $_POST['cid'];
$author = $_POST['author'];
$keyword = $_POST['keyword'];
$result1= mysql_query("update listing set catid='$catid',title='$title',
summary='$summary',content='$content', author='$author', keyword='$keyword' where pid='$pid'",$db);
include("submessage.php");
The things that are wrong with that piece of code are hard to enumerate. However, at the very least, you should establish a connection to the database before you can query it.
Why not just redirect to submessage.php rather than inlining it? Redirecting also prevents duplicate db operations when user refreshed the page. Just replace include statement with:
header('Location: submessage.php?id=' . $pid);
die();
Also, before you deploy your application: DO NOT EVER PUT USER INPUT DIRECTLY IN SQL QUERY. You should used bound parameters instead. Otherwise, you could just as well publicly advertise your database admin password. Read more on PDO and prepared statements at http://ie.php.net/pdo
Here's how I would do it:
$pdo = new PDO(....); // some configuration parameters needed
$sql = "
UPDATE listing SET
catid=:catid, title=:title, summary=:summary,
content=:content, author=:author, keyword=:keyword
WHERE pid=:pid
";
$stmt = $pdo->prepare($sql);
$stmt->bindValue('catid', $_POST['catid']);
$stmt->bindValue('title', $_POST['title']);
$stmt->bindValue('summary', $_POST['summary']);
$stmt->bindValue('content', $_POST['content']);
$stmt->bindValue('author', $_POST['author']);
$stmt->bindValue('keyword', $_POST['keyword']);
$stmt->bindValue('pid', $pid = $_GET['id']);
$stmt->execute();
header('Location: submessage.php?id=' . $pid);
die();
Or in fact, I would use some ORM solution to make it look more like that:
$listing = Listing::getById($pid = $_GET['id']);
$listing->populate($_POST);
$listing->save();
header('Location: submessage.php?id=' . $pid);
die();
Other than the usual warnings of SQL injection - very likely given your code and where you're obtaining the query parameters from (sans any kind of validation) - then it's quite possible your problem has nothing to do with the queries, particularly if it's working on subsequent attempts. Are you sure $_GET['id'] is set the first time you call the script?
Just to note, there is absolutely no reason to have to perform several update queries for each field you need to update - just combine them into a single query.