This question applies specifically to issues in the Openwall tutorial on PHP password hashing. Please read the edit below.
This question has been asked hundreds of times, but none of the answers found my issue.
$app->post("/movies", function() use ($app, $log){
$db = new mysqli(db_address,db_user,db_pass,db_database,db_port);
if ($db->connect_errno) {
$log->emergency("EM[MYSQL] Can't connect to MySQL: " . $db->error);
}
($stmt = $db->prepare("INSERT INTO movies (MovieName, MovieCover, MovieDescription, MovieDirector, MovieDate) VALUES (':title', ':cover', ':description', ':director', ':release_date')") || $log->error('ER[MYSQL] Could not prepare statement: ' . $db->error));
echo $db->error;
var_dump($stmt);
$title = grabPostVar('title');
$cover = grabPostVar('cover');
$desc = grabPostVar('desc');
$director = grabPostVar('director');
$release_date = grabPostVar('release_date');
if(!($stmt->execute(array(':title' => $title, ':cover' => $cover, ':description' => $desc, ':director' => $director, ':release_date' => $release_date))))
{
$log->emergency('EM[MYSQL] Misc issue: ' . $db->errno);
} else{
$log->info('I[MOVIE] Movie "' . $title . '" created, by user (u)$current_user(/u).');
}
$stmt->close();
$db->close();
}
On the front of this, it looks exactly the same as the other questions, but var_dump($stmt) retuns true, and according to the documentation
mysqli_prepare() returns a statement object or FALSE if an error occurred.
I used the following lines to check for this:
echo $db->error;
var_dump($stmt);
No error is printed, and var_dump yields bool(true). Any ideas? A statement very like this was working 100% very recently, but with no MySQL error return I'm completely stumped.
Edit:
Yes it was all to do with that stupid OR comparison, thank you for your answers.
if(!($stmt = $db->prepare('INSERT INTO movies (MovieName, MovieCover, MovieDescription, MovieDirector) values (?, ?, ?, ?)'))){
$log->error('ER[MYSQL] Could not prepare statment: ' . $db->error);
}
On a sidenote, I suggest that anyone following the Openwall tutorial on password hashing should change to if statements as well.
You have an issue with your parenthesis, which is causing '$stmt' to be evaluated to the result of the logical or represented by || in the line:
($stmt = $db->prepare("INSERT INTO movies (MovieName, MovieCover, MovieDescription, MovieDirector, MovieDate) VALUES (':title', ':cover', ':description', ':director', ':release_date')") || $log->error('ER[MYSQL] Could not prepare statement: ' . $db->error));
Changing it to:
($stmt = $db->prepare("INSERT INTO movies (MovieName, MovieCover, MovieDescription, MovieDirector, MovieDate) VALUES (':title', ':cover', ':description', ':director', ':release_date')")) || $log->error('ER[MYSQL] Could not prepare statement: ' . $db->error);
Will fix it, though you might consider making your code cleaner.
Related
I am trying to query large amounts of data to a server, here is my code for that:
$queryString = "";
$connect = mysqli_connect("localhost", "username", "password", "database");
$loopLength = 20;
$currentGroup = 1;
$currentLoopAmount = 0;
$queryAmount = 5;
for($v = 0; $v < ceil($loopLength / $queryAmount); $v++){
//echo "Looping Main: " . $v . "<br>";
//echo $loopLength - (($currentGroup - 1) * 10) . "<br>";
if($loopLength - (($currentGroup - 1) * $queryAmount) >= $queryAmount){
$currentLoopAmount = $queryAmount;
}
else{
$currentLoopAmount = $loopLength - (($currentGroup - 1) * $queryAmount);
}
//echo $currentLoopAmount;
$queryString = "";
for($q = (($currentGroup - 1) * $queryAmount); $q < $currentLoopAmount + (($currentGroup - 1) * $queryAmount); $q++){
//echo " Looping Sub: " . $q . "<br>";
$tempVariable = grabPageData($URLs[$q], $q);
$queryString .= $tempVariable;
if($q < $loopLength-1){
$queryString .= ",";
}
else{
$queryString .= ";";
}
}
echo $queryString;
$query = "INSERT INTO PublicNoticesTable (url, county, paperco, date, notice, id) VALUES " . $queryString;
$result = mysqli_query($connect, $query);
if($result){
echo "Success";
}
else{
echo "Failed : " . mysqli_error($connect) . "<br>";
}
$currentGroup += 1;
}
The $loopLength variable is dynamic and can be in the thousands or potentially hundred thousands. I designed this function to divide that massive number into a batch of smaller queries as I couldn't upload all the data at one time on my shared hosting service through GoDaddy. The $queryAmount variable represents how big the smaller queries are.
Here is an example of one of the value sets that gets inserted into the table:
It is the data from a public notice that my code retrieved in the grabPageData() function.
('http://www.publicnoticeads.com/az/search/view.asp?T=PN&id=37/7292017_24266919.htm','Pima','Green Valley News and Sun','2017/07/30',' ___________________________ARIZONA SUPERIOR COURT, PIMA COUNTYIn the Matter of the Estate of:JOSEPH T, DILLARD, SR.,Deceased.DOB: 10/09/1931No. PB20170865NOTICE TO CREDITORS(FOR PUBLICATION)NOTICE IS HEREBY GIVEN that DANA ANN DILLARD CALL has been appointed Personal Representative of this Estate. All persons having claims against the Estate are required to present their claimswithin four months after the date of the firat publication of this notice or the claims will be forever barred. Claims must be presented by delivering or mailing a written statement of the claim to the Personal Representative at the Law Offices of Michael W. Murray, 257 North Stone Avenue, Tucson, Arizona 85701.DATED this 17th day of July, 2017./S/ Micahel W. MurrayAttorney for the Personal RepresentativePub: Green Valley News & SunDate: July 23, 30, August 6, 2017 Public Notice ID: 24266919',' 24266919'),
To attain this data, I run it through a function that crawls the page and grabs it. Then I put the webpage html code through this function:
function cleanData($data){
$data = strip_tags($data);
//$data = preg_replace("/[^a-zA-Z0-9]/", "", $data);
//$data = mysql_real_escape_string($data);
return $data;
}
Which gives me the content without tags as you see above. Here's the problem.
The function executes and everything seems just dandy. Then the function (depending on the $queryAmount variable which I don't keep over 10 for problem's sake) outputs, as you can see it would in the function something like...
Failed : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
The weird part is that when I have large amounts of data like say the $loopLength variable is like 116. The result will output, "Failed : (error)Failed : (Error)Fai...(Error)Success. So it's only actually querying the last set of data??? Not sure.
I am not sure how to fix this and I want a fresh eye. Can somebody help me please. I have been working on this problem for... several hours trying to find solution.
Sorry for making this question a pain in the butt :(
EDIT:
I changed the code from previously to use mysql prepared statements and what not... See below:
$grabDataResults = [
"url" => "",
"county" => "",
"paperco" => "",
"date" => "",
"notice" => "",
"id" => "",
];
$connect = mysqli_connect("localhost", "bwt_admin", "Thebeast1398", "NewCoDatabase");
if($stmt = mysqli_prepare($connect, "INSERT INTO PublicNoticesTable (url, county, paperco, date, notice, id) VALUES (?, ?, ?, ?, ?, ?)")){
mysqli_stmt_bind_param($stmt, 'ssssss', $grabDataResults["url"], $grabDataResults["county"], $grabDataResults["paperco"], $grabDataResults["date"], $grabDataResults["notice"], $grabDataResults["id"]);
$loopLength = 1;
for($v = 0; $v < $loopLength; $v++){
$grabDataResults = grabPageData($URLs[$v], $v);
mysqli_stmt_execute($stmt);
printf("%d Row inserted.\n", mysqli_stmt_affected_rows($stmt));
printf("Error:\n", mysqli_stmt_error($stmt));
echo "(" . $grabDataResults["url"] . "," . $grabDataResults["county"] . "," . $grabDataResults["paperco"] . "," . $grabDataResults["date"] . "," . $grabDataResults["notice"] . "," . $grabDataResults["id"] . ")";
}
mysqli_stmt_close($stmt);
mysqli_close($connect);
}
Unfortunately this is what I get from the output:
1 Row inserted. 0 Error:
No error actually prints out and the row is inserted. However when I navigate to my database, and look at the values that have been stored.. They are all empty. The echo statement outputs this:
(http://www.publicnoticeads.com/az/search/view.asp?T=PN&id=31/7292017_24266963.htm,Yuma,Sun (Yuma), The,2017/07/30,, 24266963)
So I know that all of the variables contain something except for the $notice variable which gets destroyed by my cleanData() function for some reason.
You need to bind the data after fetching it and before executing it...
$loopLength = 1;
for($v = 0; $v < $loopLength; $v++){
$grabDataResults = grabPageData($URLs[$v], $v);
mysqli_stmt_bind_param($stmt, 'ssssss', $grabDataResults["url"],
$grabDataResults["county"], $grabDataResults["paperco"],
$grabDataResults["date"], $grabDataResults["notice"],
$grabDataResults["id"]);
mysqli_stmt_execute($stmt);
printf("%d Row inserted.\n", mysqli_stmt_affected_rows($stmt));
printf("Error:\n", mysqli_stmt_error($stmt));
echo "(" . $grabDataResults["url"] . "," . $grabDataResults["county"] . "," . $grabDataResults["paperco"] . "," . $grabDataResults["date"] . "," . $grabDataResults["notice"] . "," . $grabDataResults["id"] . ")";
}
You code is correct. Just you need to add () arround querystring
Akso you need to remove ; from query string end. SO remove following else condition
else{
$queryString .= ";";
}
change you query like :
$query = "INSERT INTO PublicNoticesTable (url, county, paperco, date, notice, id) VALUES (" . $queryString . ")";
Also it advisable to use prepared statements to prevent from sql injections
The main error I can see on your query, are the query itself. You're using a INSERT INTO with separated fields and values. But you forget to use the pharentesis on values.
Remember, the use of INSERT INTO are as follows:
First option:
INSERT INTO table field1 = value1, field2 = value2;
Second option:
INSERT INTO table (field1, field2) VALUES (value1, value2);
Also, remember to escape every field and value for avoid more errors: Example:
First option:
INSERT INTO `table` `field1` = 'value1', `field2` = 'value2';
Second option:
INSERT INTO `table` (`field1`, `field2`) VALUES ('value1', 'value2');
If you're using mysqli driver, for more security, you can use prepared statements, to get your values automatically escaped. In that case, the syntax of the query are as follows:
First option:
INSERT INTO `table` `field1` = ?, `field2` = ?;
Second option:
INSERT INTO `table` (`field1`, `field2`) VALUES (?, ?);
Also, instead of using mysqli_query(), you need to use mysqli_prepare(), mysqli_bind_param() and mysqli_execute(). You can check more data about they syntax here: http://php.net/manual/en/mysqli.prepare.php
At least, you can use mysqli_real_escape_string() function for getting your input properly escaped and checked. You can check documentation of this function here: http://php.net/manual/en/mysqli.real-escape-string.php
When inserting (or updating) a record in mysql using prepared statements and binding of values, I ran into a problem trying to insert the word child’s which contains the extended ascii character 145 (right single quotation mark). All data after the "d" is truncated. This is true for inserting any of the MS Word odd characters. My table is encoded as utf8_general_ci and I'm utf-8 all the way through in my code. The field is of type "text."
Of course I can escape them or do a str_replace() to remove them (which is what I am choosing to do), but I'd like to understand why I can't insert them directly since I always thought prepared statements handled this.
Sample insert code - incomplete, but it shows the essential
$q = "INSERT INTO mytable (userid, title, descr) VALUES (?,?,?)";
if (!($stmt = $this->mysqli->prepare($q))) {
error_log("You have a problem...");
return false;
}
/* bind parameters for markers */
$stmt->bind_param("iss", $userid, $title, $descr);
/* execute query */
$stmt->execute();
if ($stmt->errno) {
$e = new Exception;
error_log("\r\nSql Error: " . $q . ' Sql error #: ' . $stmt->errno . ' - ' . $stmt->error . "\r\n" . $e->getTraceAsString());
return false;
} else {
$lastinsertedid = $this->mysqli->insert_id;
/* close statement */
$stmt->close();
return $lastinsertedid;
}
This should not be an issue, binding the param as a string should escape any quotes as needed.
Try this to see if you can see what the error is.
$stmt = $this->mysqli->prepare($q);
if (!is_object($stmt))
error_log("You have a problem...");
var_dump($this->mysqli);
}
P.S. Don't forget $stmt->close() after $stmt->execute() as you will run into out of sync issues when attempting multiple prepared statements
I can offer some tips on syntax clean up too, take your updated question:
$q = "INSERT INTO mytable (userid, title, descr) VALUES (?,?,?)";
$stmt = $this->mysql->prepare($q);
if (!is_object($stmt))
error_log("You have a problem...");
var_dump($this->mysqli);
}
/* bind parameters for markers */
$stmt->bind_param("iss", $userid, $title, $descr);
/* execute query */
$stmt->execute();
if ($stmt->errno) {
$stmt->close(); // Still need to close here
$e = new Exception;
error_log("\r\nSql Error: " . $q . ' Sql error #: ' . $stmt->errno . ' - ' . $stmt->error . "\r\n" . $e->getTraceAsString());
return false;
}
/* close statement */
$stmt->close();
return $this->mysqli->insert_id;
The encoding for ’ was not utf8. That is the only problem. Your code may be utf8 throughout, but the data was not.
The fact that child’s truncated after the d is the symptom non-utf8 bytes being fed into otherwise good code.
Find out what application or code is generating the ’, either figure out what encoding it is generating or figure out whether it can be made to generate utf8. In the former case, we need to change one setting, in the other case, no code change need be made.
HEX('’') is E282AC in utf8.
I'm writing a generic function that will take a large number of fields from $_POST and build an SQL insert into a table. In this case, I have a number of Undefined indexes and from reading other posts on SO, I am using a ternary to test if the variable exists. This works perfectly when I use it in interactive php, especially since there are no $_POST variables defined.
But when I use it in my form, I seem to get a extra quote and a few returns but I cannot see where they are coming from. I've beaten about this in different ways but am hoping someone can help me see what I'm not seeing.
function SaveDonation($form) {
try {
$querystr = "INSERT INTO GeneralDonations(donationForm, firstName, startYear)"
. "VALUES(" . "'" . $form . "', "
. ((!isset($_POST['firstName']))
? "'', " : ("'" . mysql_real_escape_string($_POST['firstName'])."', "))
. ((isset($_POST['startDate']))
? ("'" . mysql_real_escape_string($_POST['startDate'])."' ") : "'' ")
.")";
echo "<pre>query = "; var_dump($querystr);die;
$donation = $this->db->insertRow($querystr);
$result = true;
} catch(MysqlException $e) {
$result = false;
$this->errorMsg = $e->getMessage();
}
return $result;
}
The startDate is the undefined index value. This is the browser output using var_dump. It appears that the x-debug output is showing instead of the variable. But all table, no useful data? Please help me see what's different here?
string 'INSERT INTO GeneralDonations(
donationForm, firstName, startYear)VALUES('buy-a-foot', 's',
'<br />\r\n<font size=\'1\'><table class=\'xdebug-error xe-notice\'
dir=\'ltr\' border=\'1\' cellspacing=\'0\' cellpadding=\'1\'>\r\n
<tr><th align=\'left\' bgcolor=\'#f57900\' colspan=' )' (length=284)
Your code has some problems:
Please use prepared statements (see below)!
The error message (which is not entirely shown) would continue with "Undefined index firstName", since there's an ! too much in (!isset($_POST['firstName'])).
The error message is incomplete because your xdebug shortens var_dump output. You can change this behaviour with the settings xdebug.overload_var_dump and xdebug.var_display_max_data. See xdebug documentation.
If you can't use prepared statements, consider using some sprintf() construction to improve readability.
// Prepared statements (untested)
$stmt = $db->prepare("
INSERT INTO GeneralDonations(donationForm, firstName, startYear)
VALUES (?, ?, ?)");
$stmt->execute(array(
$form,
isset($_POST['firstName']) ? $_POST['firstName'] : '',
isset($_POST['startDate']) ? $_POST['startDate'] : ''
));
I've just learning to use prepared statement in mysqli & php. Here's the snippet of the code in question.
$stmt = $mysqli->prepare ("UPDATE courses set id=?, title=?, description=?, videourl=?, article=?, colcount=?, questiondisplayed=?, onfield=? WHERE id = ?");
if ($stmt == false) { die ('prepare() failed: ' . htmlspecialchars($mysqli->error)); }
$res = $stmt->bind_param("sssssiiis", $id, $title, $description2, $videourl, $article2, $colcount, $questiondisplayed, $onfield, $oldid);
if ($res == false) { die ('bind_param() failed: ' . htmlspecialchars($mysqli->error)); }
$res = $stmt->execute();
if ($res == false) die ('execute() failed: ' . htmlspecialchars($mysqli->error));
The problem is, even after these codes run successfully (the die function never gets called), the database is not updated at all. But it's updated successfully if I'm not using prepared statement (construct the SQL query string manually). I want to convert from using manually constructed SQL query string into prepared statement. But I'm stuck in this area. Btw, the variables supplied in bind param have been set right before these codes run. I've run a print_r ($_POST); and it shows that my POST values are contain the right data. Where's the problem? Thanks.
I've update the question to further clarify
This is my first time dealing with MySQLi inserts. I had always used MySQL and directly ran the queries. Apparently, not as secure as MySQLi.
Anyhow, I’m attempting to pass two variables into the database. For some reason my prepared statement fails to do anything.
Edit: IT WORKSSS NOWWWW!!!! I added in wayyyyy more error checking. Took a bit of research, but adding checks into each function. That way I find the error code corresponding to the correct function. Once again, thank you for all your help. SURELY wouldn't of done this without you. The code listed below is now the working code
<?php
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
function InsertIPs($decimnal,$cidr)
{
$mysqli = new mysqli("localhost","jeremysd_ips","","jeremysd_ips");
if(mysqli_connect_errno())
{
echo "Connection Failed: " . mysqli_connect_errno();
exit();
}
$stmt = $mysqli->prepare("INSERT INTO subnets VALUES ('',?,?,'1','','0','0','0','0','0', '', '0', '0', NULL)");
if( false===$stmt ){
die('prepare() failed: ' . htmlspecialchars($mysqli->error));
}
$rc = $stmt->bind_param('ii',$decimnal,$cidr);
if( false===$rc ){
die('bind_param() failed: ' . htmlspecialchars($stmt->error));
}
$rc=$stmt->execute();
if( false===$rc ){
die('execute() failed: ' . htmlspecialchars($mysqli->error));
}
printf("%d Row inserted.\n", $stmt->affected_rows);
$stmt->close();
$mysqli -> close();
}
$SUBNETS = array ("2915483648 | 18");
foreach($SUBNETS as $Ip)
{
list($TempIP,$TempMask) = explode(' | ',$Ip);
echo InsertIPs($TempIP,$TempMask);
}
?>
Thank you again
Look at your pure query:
"INSERT INTO subnets
(id, subnet, mask,sectionId,description,vrfld,masterSubnetId,allowRequests,vlanId,showName,permissions,pingSubnet,isFolder,editDate)
VALUES
('',?,?,'1','','0','0','0','0','0', '{'3':'1','2':'2'}', '0', '0', NULL)"
What is that '{'3':'1','2':'2'}' which has a comma in it? Should that be reformatted so the MySQL query doesn’t choke on it? Should those values be escaped like this:
'{\'3\':\'1\',\'2\':\'2\'}'
Or perhaps with " since you seem to now indicate you need double quotes?
'{\"3\":\"1\",\"2\":\"2\"}'
Because the single quotes mixed in with that comma just seem problematic.
Or another solution is to just bind that value to the query like this:
$raw_query = "INSERT INTO subnets (id, subnet, mask, sectionId, description, vrfld, masterSubnetId, allowRequests, vlanId, showName, permissions, pingSubnet, isFolder, editDate)
VALUES ('',?,?,'1','','0','0','0','0','0',?, '0', '0', NULL)";
if($stmt = $mysqli -> prepare($raw_query))
{
$stmt-> bind_param('ii',$decimnal,$cidr,$cidr,'{"3":"1","2":"2"}');