pdo binding parameters in loop - mysql

I have following sql statement:
$sql = "UPDATE houses SET title=:title ";
which I dynamically edit according to object "location", which could have several paramaters (some of them could be null, thefore they are omitted)
//are there any location parameters which need to be added to query?
if (isset($house->location)){
//go through them and add them to query
foreach ($house->location as $key=>$locationParameter) {
$sql.=','.$key.'=:'.$key;
}
//finish query
$sql.=" WHERE id=:id";
$stmt = $db->prepare($sql);
//bind all defined location parameters to query
foreach ($house->location as $key=>$locationParameter) {
$stmt->bindParam($key, $locationParameter);
}
} else {
//there are none location parameters, so prepare just the original query with title and id
$sql.=" WHERE id=:id";
$stmt = $db->prepare($sql);
}
//and finally bind the required parameters
$stmt->bindParam("title", $house->title);
$stmt->bindParam("id", $id);
$stmt->execute();
When I echoed the query (echo $sql) it looked just as I want and also all binded parameters were right, BUT when I run the query all database columns for location parameters are updated just with the last value from location object, for example:
$house->location->lat is 25.5
$house->location->lon is 28.755
$house->location->city is munich
After execution of query with this object, the columns in DB for lat, lon, and city are all filled with "munich".
Could you tell me, what am I doing wrong?
+var_dump($sql) ->
string 'UPDATE houses SET title=:title,lat=:lat,lon=:lon,city=:city WHERE id=:id'

without reading entire question though, just caught my eye
the columns in DB for lat, lon, and city are all filled with "munich".
quoting from PDO tag wiki:
If you don't know if you need bindValue() or bindParam(), go for the former. bindValue() is less ambiguous and has lesser side effects.
most likely a cause.

Related

How can I grab multiple records from a MySQL query in Perl using array pointers?

I can do this all as one function, but in trying to port it over to my packages of functions (library) I am missing something.
Here's what I want to do from my main Perl script
my #rows;
$result = Funx::dbcdata($myConnection,
"SELECT * FROM Inv where name like \"%DOG%\";", \#rows);
Then in my library package I am attempting this
sub dbcdata
{
my ($connection, $command, $array) = #_;
my $query = $connection->prepare($command);
my $result = $query->execute();
my $i =0;
while(my $row = $query->fetchrow_arrayref() )
{
#{$array}[$i] = $row;
$i++;
}
$query->finish;
return $result;
}
I was hoping to get back pointers or references to each row (which was 4in this case) but am not. Every element in #rows is the same:
ARRAY(0x5577a0f77ec0) ARRAY(0x5577a0f77ec0) ARRAY(0x5577a0f77ec0)
ARRAY(0x5577a0f77ec0)
Nor do I know how to turn each one into the original separate row. Any help would be appreciated, thanks.
From the documentation for fetchrow_arrayref:
Note that the same array reference is returned for each fetch, so don't store the reference and then use it after a later fetch. Also, the elements of the array are also reused for each row, so take care if you want to take a reference to an element.
Sounds like you want fetchall_arrayref:
The fetchall_arrayref method can be used to fetch all the data to be returned from a prepared and executed statement handle. It returns a reference to an array that contains one reference per row.
After executing the statement, you can do something like
#{$array} = $query->fetchall_arrayref->#*;
instead of that ugly loop.
But selectall_array might be even better. Your whole function can be replaced by a call to it:
my #rows =
$myConnection->selectall_array(q/SELECT * FROM Inv WHERE name LIKE '%DOG%'/);

SQL - Database search gives error when user form input search criteria contains apostrophe

I have a database of mountains the names of which often contain an apostrophe, e.g. Beinn A'Chroin. All my search criteria work fine except when the user inputs a search via the form with the apostrophe included, i.e. Beinn A'Chroin, and then it throws up an error - Beinn A will work, Chroin will work, but never with the apostrophe. As most users will invariably insert the proper name, including the apostrophe I would prefer always to have it in the table data - Your help appreciated - Thanks John
The relative portion of my code is:
$srch = $_POST['srch'];
// Prepare query
// Named Mountain Search Search for:
if ($srch != '') { //Options for specific walk types in a specific area selected
$query = "SELECT walk, status, distance, report, dateofwalk FROM walkslist WHERE walk LIKE '%$srch%' ORDER BY walk ASC;";
update your code use PDO
try {
$conn = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
$sql = 'SELECT walk, status, distance, report, dateofwalk
FROM walkslist WHERE walk LIKE ? ORDER BY walk ASC;';
$q = $conn->prepare($sql);
$q->execute(array('%$srch%'));
$q->setFetchMode(PDO::FETCH_ASSOC);
while ($r = $q->fetch()) {
}
} catch (PDOException $pe) {
die("Could not connect to the database $dbname :" . $pe->getMessage());
}

Prepared statement fetches all the results in db, but not one I ask for

Trying to make my blog secure and learning prepared statements.
Although I set the variable, I still get all the entries from database. $escapedGet is real variable when I print it out. It's obviously a rookie mistake, but I cant seem to find an answer.
I need to get the data where postlink is $escapedGet not all the data.
$escapedGet = mysql_real_escape_string($_GET['article']);
// Create statement object
$stmt = $con->stmt_init();
// Create a prepared statement
if($stmt->prepare("SELECT `title`, `description`, `keywords` FROM `post` WHERE `postlink` = ?")) {
// Bind your variable to replace the ?
$stmt->bind_param('i', $postlink);
// Set your variable
$postlink = $escapedGet;
// Execute query
$stmt->execute();
$stmt->bind_result($articleTitle, $articleDescription, $articleKeywords);
while($stmt->fetch()) {
echo $articleTitle, $articleDescription, $articleKeywords;
}
// Close statement object
$stmt->close();
}
just tryed this: echo $escapedGet;
echo $_Get['artcile']
and got - some_other
thats the same entry that I have saved in database as postlink
tried to shande postlink to id, and then it worked. but why not with postlink tab?
When you are binding your data using 'i' modifier, it gets bound as integer.
Means string will be cast to 0 in the final statement.
But as mysql does type casting, your strings become zeroes in this query:
SELECT title FROM post WHERE postlink = 0;
try it and see - for the textual postlinks you will have all your records returned (as well as a bunch of warnings).
So, bind strings using s modifier, not i

mysql last url id always comes out to 0

$urlid = mysql_query("SELECT URL_Id FROM url ORDER BY URL_Id DESC LIMIT 1");
foreach($textnode as $key => $value) {
$value = stripslashes($value);
$value = mysql_real_escape_string($value, $con);
mysql_query("INSERT INTO paragraphs (paragraphs, URL_Id)
VALUES ('$value', '$urlid')");
}
has been returning 0 for the URL_Id column. Any suggestions ? It should be returning 1.
mysql_query function retrieving only resource object. then you need to go with looping and retrieve actual data by mysql_fetch_array() function.
i.e:
while($rowFeach = mysql_fetch_array($urlid));
print_r($rowFeach);
try this.
Thanks.
mysql_query returns a resource to the query results, not the actual selected values.
Please recheck the docs and examples in there.
(Side-note: That select could get expensive depending on the database type, and if your code has any threading, directly or indirectly (e.g. run from a web server with multiple processes), you'll get unexpected duplicate url ids).
mysql_query always returns a resource. Use either sql_fecth_assoc or mysql_fecth_array to get the values in the resource.

Perl Mysql - How to search for specific data based on one "main" match?

User Form Input - City
User Form Input - Venue
User Form Input - Cover
User Form Input - Time
User Form Input - Date
User Form Input - Number1
User Form Input - Number2
(if any are blank they are coverted to '*' on the way in. But could be whatever works.)
my $grabgig = $hookup->prepare(qq{SELECT `VenueNumber`,`Venue`,`CoverCharge`,`SetLength`,`City`,`Owner`,`Date`,`Time`,`Image1`,`Number`
FROM `gigs`
WHERE VenueNumber > ? AND `City` = ? AND `Venue` = ? AND `CoverCharge` = ?
AND Date = ? AND `Number` > ? AND `Number` < ?
AND `Time` LIKE ? LIMIT ?,?});
##########################################
$grabgig->execute('100',$city,$venue,$cover,'*',$number1,$number2,?,'0','6')
or die "Did not execute";
That is a basic example above.
I want to be able to return results based on the City Input.
If more input is present, then narrow down results accordingly.
But the query returns nothing if fields are empty (*).
I tried wildcards and so on then, I experimented with LIKE and NOT LIKE.
This seemingly simple search is driving me nuts.
Can someone help this newbie?
OK, I'm pretty unsure what you mean, BUT, my best undererstanding of what you're trying to do is to query like you do now BUT if a particular field is not populated in the form, to avoid adding that field to the where clause; as opposed to current query which instead does and myField="*".
Correct?
If that's so, you need to build your query, and replacement list, in pieces:
my $sql = qq{SELECT MY_FIELD_LIST_TOO_LAZY_TO_TYPE FROM `gigs` WHERE 2=2};
my #replacement_values = (); # These go into execute() instead of "?"s
if ($city ne "*") {
$sql .= qq[AND city = ?];
push #replacement_values, $city;
}
if ($number1 ne "*") {
$sql .= qq[AND number > ?];
push #replacement_values, $number1;
}
# ... more values processed the same way
my $grabgig = $hookup->prepare($sql);
$grabgig->execute(#replacement_values) or die "Did not execute";
If you want to do it more intelligently (i.e. to generalize), you will have the form fields in a hash; have a config hash mapping the form field name to the DB column name and the operator, and instead do the above as:
my %fields = (
city => ["city" , "="]
,number1 => ["number", ">"]
,number2 => ["number", "<"]
);
my $sql = qq{SELECT MY_FIELD_LIST_TOO_LAZY_TO_TYPE FROM `gigs` WHERE 2=2};
my #replacement_values = (); # These go into execute() instead of "?"s
foreach my $field (keys %form_data) {
next unless exists $fields{$field};
if ($form_data{$field} ne "*") {
$sql .= qq[ AND $fields{$field}->[0] $fields{$field}->[1] ?];
push #replacement_values, $form_data{$field};
}
}
my $grabgig = $hookup->prepare($sql);
$grabgig->execute(#replacement_values) or die "Did not execute";
I am assuming that you want to construct a query where only a few input parameters have valid values and the rest are undefined. If that is indeed what you want, here is what you could do: Construct the query dynamically. Here are the steps you could take assuming you are using CGI.pm and assuming that the where clause is just a series of "this = that" - In your case you have different operators - but the idea is the same.
First construct a "where" string from the CGI query parameter (Sorry untested code):
my $qrystr = '';
foreach ($query->param) {
if (my $val = $query->param($_)) {
$qrystr .= "where $_ = " . $dbh->quote($val) . ' and ';
}
}
$qrystr .= "where 1 = 1";
Now you can just prepare and execute the query : "select * from table $qrystr"
If you want automatic quoting you will have to use bind parameters which is an easy extension of the code above
Update There was a missing "where" in the last true clause "1 = 1" - Sorry, added it now
Sorry, the formatting bar was not appearing so, I rebooted. Now I cannot edit my question or comment.
What I am trying to do is provide a search for the users.
They select a city from a dropdown then some optional data can be entered / selected to narrow the results.
The optional data May or May Not be present in the table, could be a blank field.
I would like the results to show based on the selected criteria of the search in that City.
So, WHERE selected "input city" = "tables city column" look for the other options (ignore that particular criteria if field is empty) and return any matches that exist for that city.
I am then pushing into array in a While for output display.
I guess it would be like a car query. Select make where doors = 2 and color = red and engine = hamsterwheel but, the color field may be empty in the database..