I have a cronjob which runs a script -> getting data from different itunes stores. Sometimes i get the above mentioned error message.
I think its because of special letters or something like this. Is there a way to check, where the problem exactly is? Which "special character" is respsonisble for the error. Is there a workaround for example with a IF statement?
I canĀ“t reproduce the error, as it not appears always. Would be great to get help on this.
Here is the code:
foreach ($Kategorien->entry as $item) {
$id = addslashes($item->id);
$title = utf8_decode(addslashes($item->title));
$preview = addslashes($item->link[1]["href"]);
$namespaces = $item->getNameSpaces(true);
$im = $item->children($namespaces['im']);
$track_title = utf8_decode(addslashes($im->name));
$track_artist = utf8_decode(addslashes($im->artist));
$track_amount = addslashes($im->price->attributes()->amount);
$track_currency = utf8_decode(addslashes($im->price->attributes()->currency));
$release_date = addslashes($im->releaseDate);
$image = addslashes($im->image[2]);
$entry_id['im'] = $item->id->attributes('im', TRUE);
$track_id = addslashes($entry_id['im']['id']);
$category_id['im'] = $item->category->attributes('im', TRUE);
$genre_id = addslashes($category_id['im']['id']);
$genre_cat = utf8_decode(addslashes($item->category->attributes()->term));
$insertSQL = sprintf("UPDATE track_itunes_countries_total SET modified = NOW(), modified_genre = '$genre_name' WHERE id = ".$row_select_country['id']."");
$Result1 = mysql_query($insertSQL, $con) or die(mysql_error());
$insertSQL = sprintf("INSERT INTO track_itunes_".$cc."_total (id, title, preview, track_title, track_artist, track_amount, track_currency, release_date, image, track_id, genre_id, genre_cat, country, Online, Approved) VALUES ('$id', '$title', '$preview', '$track_title', '$track_artist', '$track_amount', '$track_currency', '$release_date', '$image', '$track_id', '$genre_id', '$genre_cat', '$cc', '1', '1') ON DUPLICATE KEY UPDATE title='$title',preview='$preview',track_title='$track_title',track_artist='$track_artist',track_amount='$track_amount',track_currency='$track_currency',release_date='$release_date',image='$image',track_id='$track_id',genre_id='$genre_id',genre_cat='$genre_cat',country='$cc'");
$Result1 = mysql_query($insertSQL, $con);}
I will answer in a tangential way, because you're using mysql_* library which is deprecated and show you PDO instead. This will either a) solve your problem or b) provide a much more informative error message that will help you debugging.
foreach ($Kategorien->entry as $item) {
$id = $item->id;
$title = utf8_decode($item->title);
$preview = $item->link[1]["href"];
$namespaces = $item->getNameSpaces(true);
$im = $item->children($namespaces['im']);
$track_title = utf8_decode($im->name);
$track_artist = utf8_decode($im->artist);
$track_amount = $im->price->attributes()->amount;
$track_currency = utf8_decode($im->price->attributes()->currency);
$release_date = $im->releaseDate;
$image = $im->image[2];
$entry_id['im'] = $item->id->attributes('im', TRUE);
$track_id = $entry_id['im']['id'];
$category_id['im'] = $item->category->attributes('im', TRUE);
$genre_id = $category_id['im']['id'];
$genre_cat = utf8_decode($item->category->attributes()->term);
$insertSQL = "UPDATE track_itunes_countries_total
SET modified = NOW(), modified_genre = :genre_name
WHERE id = :row_id");
$stmt = $pdo->prepare($insertSQL);
$stmt->bindValue(':genre_name', $genre_name);
$stmt->bindValue(':row_id', $row_select_country['id']);
$success = $stmt->execute();
if(!$success){
//something bad happened
}
//use whitelist techniques to guarantee valid, non-malicious input
//with table names or column names. whitelistTableName is a function
//that YOU have to write.
$clean_table_name = whitelistTableName("track_itunes_{$cc}_total");
$insertSQL = "INSERT INTO {$clean_table_name}
(id, title, preview, track_title,
track_artist, track_amount, track_currency,
release_date, image, track_id, genre_id,
genre_cat, country, Online, Approved)
VALUES
(:id, :title, :preview, :track_title,
:track_artist, :track_amount, :track_currency,
:release_date, :image, :track_id, :genre_id,
:genre_cat, :country, :Online, :Approved)
ON DUPLICATE KEY UPDATE
title=:title_u,preview=:preview_u,track_title=:track_title_u,
track_artist=:track_artist_u,track_amount=:track_amount_u,
track_currency=:track_currency_u,release_date=:release_date_u,
image=:image_u,track_id=:track_id_u,genre_id=:genre_id_u,
genre_cat=:genre_cat_u,country=:cc_u");
$stmt = $pdo->prepare($insertSQL);
$stmt->bindValue(':id', $id);
$stmt->bindValue(':title', $title);
$stmt->bindValue(':preview', $preview);
$stmt->bindValue(':track_title', $track_title);
$stmt->bindValue(':track_artist', $track_artist);
$stmt->bindValue(':track_amount', $track_amount);
$stmt->bindValue(':track_currency', $track_currency);
$stmt->bindValue(':release_date', $release_date);
$stmt->bindValue(':image', $image);
$stmt->bindValue(':track_id', $track_id);
$stmt->bindValue(':genre_id', $genre_id);
$stmt->bindValue(':genre_cat', $genre_cat);
$stmt->bindValue(':country', $cc);
$stmt->bindValue(':Online', 1);
$stmt->bindValue(':Approved', 1);
//some drivers doesn't allow to have a named placeholder to appear more than once so we must duplicate those.
$stmt->bindValue(':id_u', $id);
$stmt->bindValue(':title_u', $title);
$stmt->bindValue(':preview_u', $preview);
$stmt->bindValue(':track_title_u', $track_title);
$stmt->bindValue(':track_artist_u', $track_artist);
$stmt->bindValue(':track_amount_u', $track_amount);
$stmt->bindValue(':track_currency_u', $track_currency);
$stmt->bindValue(':release_date_u', $release_date);
$stmt->bindValue(':image_u', $image);
$stmt->bindValue(':track_id_u', $track_id);
$stmt->bindValue(':genre_id_u', $genre_id);
$stmt->bindValue(':genre_cat_u', $genre_cat);
$stmt->bindValue(':country_u', $cc);
$stmt->bindValue(':Online_u', 1);
$stmt->bindValue(':Approved_u', 1);
$success = $stmt->execute();
if(!$success){
//something bad happened
}
}
more to read here: http://php.net/manual/en/book.pdo.php It's pretty easy and much better than mysql_* libraries
Expanding on the whitelisting techniques: there are several approaches to sanitize user inputs. One is escaping: this is done where the user input is "open ended" like a text input, where there is an unlimited number of possibilities. Prepared statements are perfect for this, as demonstrated above.
Another possibility is whitelisting, and it's useful when there are only limited valid possibilities for the user input (for example, radiobuttons, checkboxes, option selections, etc.) and any invalid input is either an error or malicious.
an example follows:
whitelistTableName($tablename){
$allowedTables = array('tbl1', 'tbl2', 'tbl3');
if(in_array($tablename, $allowedTables)){
return $tablename;
} else {
throw new Exception('Malicious attempt detected');
}
}
This is very basic but allows you to get started. A better approach would be to query your information_schema database to fetch every valid table name rather than hardcoding them by hand.
That's not how sprintf works.
sprintf means string printf -- you are doing a printf which returns a string instead of printing directly into stdout.
printf works by assigning placeholders into a format string (the first argument), and the bound values to the placeholders as the succeeding arguments.
for example
$s = sprintf("SELECT * FROM %s WHERE id = %d", 'some_table', $id);
This is in some way a naive way to sanitize input since you are forcing variables to be cast into certain types using the formats: in this case %s and %d for string and decimal/digit, respectively. At runtime, these will be replaced by "some_table", and whatever intval($id) is.
The reason you are getting "Too few arguments" is because you are missing the bound values.
First of all: you should use mysql_real_escape_string() or even better use mysqli instead of mysql functions since mysql is deprecated.
And for the errormessage you should have a look into the documentation of sprintf to understand the error.
Or just use proper concatination.
$string = "fooo='".$var."'";
instead of your lazy notation
$string = "fooo='$var'";
Here is an example including mysql_real_escape_string():
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
You can also give specific positions for the bound vars:
$query = sprintf("SELECT * FROM users WHERE user='%2$s' AND password='%1$s'",
mysql_real_escape_string($password),
mysql_real_escape_string($user)
);
And for the mysql_query(), you don't need to supply the connection link $con if you don't use more then 1 database connection.
mysql_query($query);
will do the trick.
Related
This question already has answers here:
Single result from database using mysqli
(6 answers)
Closed 2 years ago.
I am trying to write a function that will check for a single value in the db using mysqli without having to place it in an array. What else can I do besides what I am already doing here?
function getval($query){
$mysqli = new mysqli();
$mysqli->connect(HOST, USER, PASS, DB);
$result = $mysqli->query($query);
$value = $mysqli->fetch_array;
$mysqli->close();
return $value;
}
How about
$name = $mysqli->query("SELECT name FROM contacts WHERE id = 5")->fetch_object()->name;
The mysql extension could do this using mysql_result, but mysqli has no equivalent function as of today, afaik. It always returns an array.
If I didn't just create the record, I do it this way:
$getID = mysqli_fetch_assoc(mysqli_query($link, "SELECT userID FROM users WHERE something = 'unique'"));
$userID = $getID['userID'];
Or if I did just create the record and the userID column is AI, I do:
$userID = mysqli_insert_id($link);
Always best to create the connection once at the beginning and close at the end. Here's how I would implement your function.
$mysqli = new mysqli();
$mysqli->connect(HOSTNAME, USERNAME, PASSWORD, DATABASE);
$value_1 = get_value($mysqli,"SELECT ID FROM Table1 LIMIT 1");
$value_2 = get_value($mysqli,"SELECT ID FROM Table2 LIMIT 1");
$mysqli->close();
function get_value($mysqli, $sql) {
$result = $mysqli->query($sql);
$value = $result->fetch_array(MYSQLI_NUM);
return is_array($value) ? $value[0] : "";
}
Here's what I ended up with:
function get_col($sql){
global $db;
if(strpos(strtoupper($sql), 'LIMIT') === false) {
$sql .= " LIMIT 1";
}
$query = mysqli_query($db, $sql);
$row = mysqli_fetch_array($query);
return $row[0];
}
This way, if you forget to include LIMIT 1 in your query (we've all done it), the function will append it.
Example usage:
$first_name = get_col("SELECT `first_name` FROM `people` WHERE `id`='123'");
Even this is an old topic, I don't see here pretty simple way I used to use for such assignment:
list($value) = $mysqli->fetch_array;
you can assign directly more variables, not just one and so you can avoid using arrays completely. See the php function list() for details.
This doesn't completely avoid the array but dispenses with it in one line.
function getval($query) {
$mysqli = new mysqli();
$mysqli->connect(HOST, USER, PASS, DB);
return $mysqli->query($query)->fetch_row()[0];
}
First and foremost,
Such a function should support prepared statements
Otherwise it will be horribly insecure.
Also, such a function should never connect on its own, but accept an existing connection variable as a parameter.
Given all the above, only acceptable way to call such a function would be be like
$name = getVal($mysqli, $query, [$param1, $param2]);
allowing $query to contain only placeholders, while the actual data has to be added separately. Any other variant, including all other answers posted here, should never be used.
function getVal($mysqli, $sql, $values = array())
{
$stm = $mysqli->prepare($sql);
if ($values)
{
$types = str_repeat("s", count($values));
$stm->bind_param($types, ...$values);
}
$stm->execute();
$stm->bind_result($ret);
$stm->fetch();
return $ret;
}
Which is used like this
$name = getVal("SELECT name FROM users WHERE id = ?", [$id]);
and it's the only proper and safe way to call such a function, while all other variants lack security and, often, readability.
Try something like this:
$last = $mysqli->query("SELECT max(id) as last FROM table")->fetch_object()->last;
Cheers
So I am attempting to write a generic sqlite insert that can be used no matter how many items a row has. This is for a single row, assumes all columns other than ID, which is set to autoincrementing integer, are assigned, and bindparam must be used. I have been attempting it like so:
Table Quarterbacks
ID---firstName---lastName
public static function insert($table, $values)
{
$pdo = new PDO('sqlite:testTable.sqlite');
$inputString = implode(",", $values);
$statement = $pdo->prepare("insert into $table values (:value)");
$statement->bindParam(':value', $inputString);
$statement->execute();
}
$new = array("Steve", "Young");
Query::insert("Quarterbacks", $new);
The idea being that the table will now add a new row, increment the ID, and add Steve Young. But I get the generic error that the prepare statement is false. I know my pdo is connecting to the database, as other test methods work. There's a lot of array related threads out there but it seems like they're much more complicated than what I'm trying to do. I'm pretty sure it has to do with it treating the single string as invalid, but it also won't take an array of strings for values.
Edit:I'm starting to lean towards a compromise like bash, ie provide a large but not infinite amount of function parameters. Also open to the ...$ style but I feel like that ends up with the same problem as now.
I was able to get this to work
$name = "('daunte' , 'culpepper')";
$cats = "('firstName', 'lastName')";
$statement = $pdo->prepare("insert into $table" .$cats ." values" .$name);
$statement->execute();
But not this
$name = "('reggie' , 'wayne')";
$cats = "('firstName', 'lastName')";
$statement = $pdo->prepare("insert into $table:cats values:name");
$statement->bindParam(':cats', $cats);
$statement->bindParam(':name', $name);
$statement->execute();
So I'm using PHP to take the contents of a csv file, put it into a string array and then use SQL to add it to a database on an IBM iSeries.
However PHP keeps trying to treat the contents of the string (which contains special characters like "*" and "-") like a mathematical computation.
How do I prevent this?
here is the code in question
if (($handle = fopen($_FILES['uploadcsv']['tmp_name'], "r")) !== FALSE)
{
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE)
{
$length = count($data);
$s_data = implode(',', $data);
if($length > $maxcol)
{
// echo $length;
// die;
$uploadMsg = "Data Error: Not ($maxcol) Columns: ($s_data) <br>";
}
else
{
if($data[0] <> '')
{
$recda[0] = trim($data[0]); // qty = 1 roll
// Prepare the SQL statement (possibly faster, safer, better practice)
$insertsql = "INSERT INTO MIKELIB/PALLETS (PALLET)
VALUES($recda[0]) with nc";
$stmt = db2_prepare($db2conn, $insertsql);
//$result = db2_exec($db2conn, "Insert into file ...$data[0]"
$result = db2_execute($stmt, $data[0]);
if(!$result)
{
$uploadMsg .= "Result code: " . $result . "Data Error: " . db2_stmt_error() . " msg: " . db2_stmt_errormsg() . "data: ($s_data)<br>";
}
else
{
$s_data = implode(',', $recda);
$uploadMsg .= "Added row ($s_data)<br>";
}
}
}
}
fclose($handle);
}
Here is an example output of the error "Result code: Data Error: 42604 msg: Numeric constant 5D09C not valid. SQLCODE=-103data: (A2501-0044*970*5D09C*034)"
Actually, it's your database that is parsing your data as math.
Take a look at this line:
$insertsql = "INSERT INTO MIKELIB/PALLETS (PALLET)
VALUES($recda[0]) with nc";
$stmt = db2_prepare($db2conn, $insertsql);
You're putting the values directly into the query, so if the query has math, or invalid symbols, it'll break your query.
What you should do is:
$insertsql = "INSERT INTO `MIKELIB/PALLETS` (PALLET)
VALUES(?) with nc";
$stmt = db2_prepare($db2conn, $insertsql);
$recda0 = $recda[0];
db2_bind_param($stmt, 1, "recda0", DB2_PARAM_IN);
That way, there's nothing in $recda[0] that will break the query, or be parsed as part of the query.
Joesph, try modifing your SQL to treat that value as a string by wrapping it in single quotes.
$insertsql = "INSERT INTO MIKELIB/PALLETS (PALLET)
VALUES('$recda[0]') with nc";
You may also need to consider escaping single quotes in the string if there is a possibility it will contain any.
I get the impression that you may be trying to load values into multiple columns per row. That won't work in SQL. You have to specify each column.
I know DB2 for i, but not PHP, so I'll attempt to build on David's answer as a template.
$insertsql = "INSERT INTO MYLIB/MYTABLE (cola, colb, colc)
VALUES(?,?,?) with nc";
$stmt = db2_prepare($db2conn, $insertsql);
$vala = $recda[0];
$valb = $recda[1];
$valc = $recda[2];
db2_bind_param($stmt, 1, "vala", DB2_PARAM_IN);
db2_bind_param($stmt, 2, "valb", DB2_PARAM_IN);
db2_bind_param($stmt, 3, "valc", DB2_PARAM_IN);
You may need additional PHP code, perhaps to make sure each value is appropriate for its column, and might perhaps need to detect missing values and load a null or default value, depending on your table definition. But I'll leave that to those who know PHP.
I am trying do multi-driver support for my Framework, which basically means I can use MySQL, MySQLi or PDO(MySQL) with ease.
So, let's say I have an array of values I want to insert.
array('Manuel', 'StackOverflow');
and I have this query..
mysql_query("INSERT INTO users(name, fav_site) VALUES(?, ?)");
So, I'd like to replace the question marks with those values in order, so Manuel goes first and then goes StackOverflow. Remembering that I need to add -> ' <- at the sides of these values so MySQL doesn't throw an error.
I have tried searching if someone has asked this and had no luck.
Any help is appreciated!
NOTE: I know I shouldn't even bother with MySQL, but hey! A feature is a feature.
<?php
$query = "INSERT INTO users(name, fav_site) VALUES(?, ?)";
$args = array('joe', 'google goggles');
while(strpos($query, '?') !== FALSE)
{
$query = preg_replace('/\?/', your_quoting_func(array_shift($args)), $query, 1);
}
echo $query;
Basically, this says...while there is still a ? remaining in the string, delete the first question mark and replace it with a quoted (use your own function or mysql_real_escape_string and surround with single quotes) string, and shift that item off the array. You should probably substr_count the ? marks versus the number of arguments for error checking.
I used preg_replace because it accepts an argument specifying how many values to replace, whereas str_replace does not.
I would do it this way (with one exeption: I wouldn't use mysql_):
<?php
$values = array('foo', 'bar');
$query_start = "INSERT INTO `users` (`name`, `fav_site`) VALUES ('";
$query_end = "')";
$query = $query_start . implode("', '", $values) . $query_end;
$result = mysql_query($query);
?>
$query_start contains the start of the MySQL query (notice the ' at the end), and $query_end goes at the end.
Then $values is imploded, with ', ' as the 'glue', and $result is set as:
$query_start (impoded $result) $query_end.
See implode - PHP Manual.
Hey guys, I'm using smarty and php I am trying to make this function work
{foreach $rows as $row}
<input type="checkbox" name="likes[]" value="{$row.ID}">{$row.Interests}<br>
{/foreach}
That there is the html/template for checkboxes, it grabs data from a table in my database
Now I am trying to store data into my database
// $likes = mysql_escape_string($likes);
$connection = mysql_open();
$insert = "insert into Users " .
"values (null, '$firstName', '$lastName', '$UserName', '$email', from_unixtime('$DOB'), '$join', '$gender')";
$result = # mysql_query ($insert, $connection)
or showerror();
$id = mysql_insert_id();
//echo $id; testing what it gets.
mysql_close($connection);
$connection = mysql_open();
foreach($likes as $like)
{
$insert3 = "insert into ProfileInterests " .
"values ('$id', '$like', null)";
$result3 = # mysql_query ($insert3, $connection)
or showerror();
}
mysql_close($connection)
or showerror();
}
That there is the script I am using to enter data into my database...there is more above which is just cleaning the user input really.
mysql_open() is my own function, so don't worry too much about that.
$likes = #$_POST['likes'];
that is what I am using to get the likes....I feel that this is wrong. I am not sure what to do....
I get this error at the moment. Invalid argument supplied for foreach()
I think this is completely to do with the variable $likes, I think it's not being treated like an array...any idea on what I should do.. I am quite a newbie.
The following line :
$likes = join(",",$likes);
is transforming your $likes array to a $likes string, containing the values and separating them by commas.
So, later, when you try to loop over $likes, its no longer an array : it's a string -- which explains the Invalid argument supplied for foreach().
Edit after the comment : when calling the following line :
$likes = mysql_escape_string($likes);
If your $likes is an array, you'll get some trouble, as mysql_escape_string works on a string.
Instead of trying to escape the whole array at once, you should use mysql_escape_string on each item, while looping over the array -- a bit like that :
foreach($likes as $like)
{
// escape the current item :
$escaped_like = mysql_real_escape_string($like);
$insert3 = "insert into ProfileInterests values ('$id', '$escaped_like', null)";
$result3 = # mysql_query ($insert3, $connection) or showerror();
}
As a sidenote : you should use var_dump() on your variables, while developing, to see what they contain ;-) It'll help you understand what your code is doing.