I'm making a function to query my database, fully, with a keyword search ($wordsToSearch) or with some category tags words($tagsToSearch) if there are.
This is my function, and it's not secure since i use the concat to add some part of the query. How should I use PDO to filter the variabiles and then add the part of the query when it is necessary?
Thanks to everybody
$wordsToSearch = " ";
$tagsToSearch = " ";
if(is_string($search)){
$wordsToSearch = "WHERE (
`artist_nm` LIKE '%".$search."%'
OR `place` LIKE '%".$search."%'
)";
}
if(is_string($searchtags)){
$arrayTags = explode(',', $searchtags);
$tagsToSearch = "HAVING (
`tags` LIKE '%".$arrayTags[0]."%' ";
foreach ($arrayTags as $key => $value) {
if($key != 0 && $key <= 20) {
$tagsToSearch .= "OR `tags` LIKE '%".$value."%' ";
}
}
$tagsToSearch .= ")";
}
$database->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$STH = $database->prepare('SELECT id, lat, lng, CONCAT_WS( "/&/", total, tags ) AS data
FROM (SELECT lat, lng, id, CONCAT_WS( "/&/", img_link, artist_nm, page_link, place, Total_Rating, Rating_Number ) AS total, GROUP_CONCAT( tag_name
SEPARATOR "," ) AS tags
FROM images
LEFT OUTER JOIN tbl_places ON images.id = tbl_places.KE_img
LEFT OUTER JOIN rel_tags ON images.id = rel_tags.Id_immagine
LEFT OUTER JOIN tags ON tags.Id_tag = rel_tags.Id_tag
'.$wordsToSearch.'
GROUP BY id '.$tagsToSearch.'
) AS subquery
');
try {
$STH->execute();
} catch(PDOException $e){
echo $e->getMessage();
die();
}
You are looking for prepared requests. You have to put compile your query with some parameters with prepare() method:
<?php
// With placeholders
$sth = $database->prepare('SELECT * FROM table WHERE id = ?');
// With named parameters
$sth = $database->prepare('SELECT * FROM table WHERE id = :id');
?>
Then you can execute the query using execute() method:
<?php
// With placeholders
$sth->bindParam(1, $yourId, PDO::PARAM_INT);
$sth->execute();
// or
$sth->execute(array($yourId));
// With named parameters
$sth->bindParam(':id', $yourId, PDO::PARAM_INT);
$sth->execute();
// or
$sth->execute(array(':id' => $yourId));
?>
Edit:
Of course you can put more than one parameter:
<?php
// With placeholders
$sth = $database->prepare('SELECT * FROM table WHERE username = ? AND password = ?');
$sth->bindParam(1, $username, PDO::PARAM_STR);
$sth->bindParam(2, $password, PDO::PARAM_STR);
$sth->execute();
// or
$sth->execute(array($username, $password));
// With named parameters
$sth = $database->prepare('SELECT * FROM table WHERE username = :username AND password = :password');
$sth->bindParam(':username', $username, PDO::PARAM_STR);
$sth->bindParam(':password', $password, PDO::PARAM_STR);
$sth->execute();
// or
$sth->execute(array(':username' => $username, ':password' => $password));
?>
More information in the documentation.
Related
I have a running ms sql server and want some data copied to a mysql database.
i already can connect to them both so i made something like:
$pdo = new PDO('SQLSERVER', $user, $password);
$sql = "SELECT id, name FROM users";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$json_users = array();
while ($row = $stmt->fetchObject()){
$json_users[] = $row;
}
$pdo = new PDO('MYSQLDB', $user, $password);
foreach ($json_users as $key => $value){
$sql = "INSERT INTO users (id, name) VALUES (:id, :name)"
$stmt = $pdo->prepare($sql);
$stmt->bindParam('id', $value->id, PDO::PARAM_INT);
$stmt->bindParam('name', $value->name, PDO::PARAM_STR);
$stmt->execute();
}
this does work but takes a lot of time cause its a big table.
so my question is can i insert the complete results from sqlserver to mysql at once with only one insert query? without the foreach?
Update: the table contains 173398 rows and 10 columns
With prepared statements (especially for multi-insert) you want to have your prepared statement outside your loop. You only need to set the query up once, then supply your data in each subsequent call
$sql = "INSERT INTO users (id, name) VALUES (:id, :name)";
$stmt = $pdo->prepare($sql);
foreach($json_users as $key => $value){
$stmt->bindParam('id', $value->id, PDO::PARAM_INT);
$stmt->bindParam('name', $value->name, PDO::PARAM_STR);
$stmt->execute();
}
You can export this into CSV file first from MSSQL then import that file into MySQL.
$pdo = new PDO('SQLSERVER', $user, $password);
$sql = "SELECT id, name FROM users";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$fp = fopen('/tmp/mssql.export.csv', 'w');
while ($row = $stmt->fetch(PDO::FETCH_NUM)){
fputcsv($fp, array_values($row));
}
fclose($fp);
$pdo = new PDO('MYSQLDB', $user, $password, array(PDO::MYSQL_ATTR_LOCAL_INFILE => 1));
$sql = <<<eof
LOAD DATA LOCAL INFILE '/tmp/mssql.export.csv'
INTO TABLE user_copy
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
(id,name)
eof;
$pdo->exec($sql);
one drawback with the above, you need to have this configuration enabled in my.cnf ( MySQL configuration )
[server]
local-infile=1
Since MySQL cannot read files that are owned by others unless it it opened with --local-infile=1
I would suggest not bind values, but generate the query string:
$sql = "";
foreach ($json_users as $key => $value){
if ($sql=="") {
$sql = "INSERT INTO users (id, name) VALUES ";
$sql =." (".$value->id.',"'.$value->name.'")';
} else {
$sql .= ", (".$value->id.',"'.$value->name.'")';
}
}
$stmt = $pdo->prepare($sql);
$stmt->execute();
It is not best practice, but since you trust data source it could help.
Consider doing bulk inserts instead of one row at a time.
$sourcedb = new \PDO('SQLSERVER', $sourceUser, $sourcePassword);
$targetdb = new \PDO('MYSQLDB', $targetUser, $targetPassword);
$sourceCountSql = "SELECT count(*) count FROM users;";
/**
* for mssql server 2005+
*/
$sourceSelectSql = "
SELECT
id,
name
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY id) RowNum,
id,
name
FROM
users
) users
WHERE
RowNum >= %d
AND RowNum < %d
ORDER BY
RowNum
";
/**
* for mssql server 2012+
*/
$sourceSelectSql = "
SELECT
FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
SELECT
id,
name
FROM
users
ORDER BY
id
OFFSET %d ROWS
FETCH NEXT %d ROWS ONLY
";
$sourceCount = $sourcedb->query($sourceCountSql, \PDO::FETCH_COLUMN, 0);
$rowCount = 1000;
$count = 0;
$count2 = 0;
for($x = 0; $x < $sourceCount; $x += $rowCount) {
$sourceRecords = $sourcedb->query(sprintf($sourceSelectSql, $x, $rowCount), \PDO::FETCH_ASSOC);
$inserts = [];
foreach($sourceRecords as $row) {
$inserts[] = sprintf("(:id_%1$d, :name_%1$d)", $count++);
}
$stmt = $targetdb->prepare(sprintf("INSERT INTO users (id, name) VALUES %s;", implode(',', $inserts));
foreach($sourceRecords as $row) {
$stmt->bindParam(sprintf('id_%d', $count2), $row['id'], \PDO::PARAM_INT);
$stmt->bindParam(sprintf('name_%d', $count2), $row['name'], \PDO::PARAM_STR);
$count2++;
}
$targetdb->execute();
unset($inserts);
}
I am having a problem with binding param or value, does anybody knows what wrong?
If i change ? to area it works :-$
$item = 'area';
$query = dbConnectionPDO::getConnect()->prepare( ' SELECT * FROM ? ' );
$query->bindParam(1, $item, PDO::PARAM_STR);
$query->execute();
while($resultId = $query->fetch(PDO::FETCH_ASSOC)){
////
}
Is this a good solution? It works!
$select = 'select * from ' . $item . ' left join ' . $TableName . ' ';
$query = dbConnectionPDO::getConnect()->prepare("$select ON :three = :four");
$query->bindValue(':three', $three, PDO::PARAM_STR);
$query->bindValue(':four', $four, PDO::PARAM_STR);
$query->execute();
while($resultId = $query->fetch(PDO::FETCH_ASSOC)){
////
}
You're trying to bind a table name, not a parameter. I'm not sure you can actually do that.
bindParam works by binding question-mark holders or named parmeters, not a table name.
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?');
$sth->bindParam(1, $calories, PDO::PARAM_INT);
$sth->bindParam(2, $colour, PDO::PARAM_STR, 12);
$sth->execute();
If you're just looking into placeholder "replacement" you can just use sprintf, but be careful since if you'll be doing anything fishy or stupid (like accepting the table name from an external source), it might be leaky.
For example:
$theQ = "SELECT * FROM `%s` LEFT JOIN `%s` ON `%s` = `%s`";
$runQ = sprintf($theQ, 'one', 'two', 'three', 'four');
You need to provide a valid SQL statement where only literals are parametrized. Even if the database driver is dumb enough to accept the query, you'll end up executing something like:
SELECT * FROM 'area'
... which is obviously not what you intended.
You cant parametrize a table name, only parameters.
I have other PDO Statements that execute fine, but this one is screwed up.
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->execute( array( 0, 10 ) );
The above does NOT work, but the below does work:
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT 0,10' );
$sth->execute( array( 0, 10 ) );
So why won't the first way display any of my results when it should be giving the same response?
So here is what I have now
$start = 0;
$perpage = 10;
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->bindValue(1, $start, PDO::PARAM_INT);
$sth->bindValue(2, $perpage, PDO::PARAM_INT);
$sth->execute();
this also does not work
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->bindParam(1, 0, PDO::PARAM_INT);
$sth->bindParam(2, 10, PDO::PARAM_INT);
$sth->execute();
The problem is likely that PDO will interpret any inputs as strings. You can try
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT :low,:high' );
$sth->bindValue(':low', 0, PDO::PARAM_INT);
$sth->bindValue(':high', 10, PDO::PARAM_INT);
$sth->execute();
Or
$low = 0;
$high = 10;
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT :low,:high' );
$sth->bindParam(':low', $low, PDO::PARAM_INT);
$sth->bindParam(':high', $high, PDO::PARAM_INT);
$sth->execute();
Source: How to apply bindValue method in LIMIT clause?
Not sure if you saw this question but have you tried casting the values you send as ints?
$start = 0;
$perpage = 10;
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->bindValue(1, (int)$start, PDO::PARAM_INT);
$sth->bindValue(2, (int)$perpage, PDO::PARAM_INT);
$sth->execute();
Or it says to do this:
$start = 0;
$perpage = 10;
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT ?,?' );
$sth->bindValue(1, intval($start), PDO::PARAM_INT);
$sth->bindValue(2, intval($perpage), PDO::PARAM_INT);
$sth->execute();
This is because "prepare" and execute with array argument thinks your datas are string by default. So they escape them with ' '. THe problem is that when you deal with limits those quotes trigger error.
The solution is bindValue
$sth = $dbh->prepare( 'SELECT * FROM `post` LIMIT :number OFFSET :start' );
$sth->bindValue("number",10, PDO::PARAM_INT);
$sth->bindValue("start",0,PDO::PARAM_INT);
$sth->execute();
What database? MySQL? SQL Server? Oracle?
In MySQL the PDO with LIMIT clause should work as in GlaciesofPacis's post. However, if you are using SQL SERVER you're not using the correct syntax. Referenced from StackOverflow question:
$query = "
DECLARE #Sort
SET ROWCOUNT :startRow
SELECT #Sort = SortColumn FROM Table ORDER BY SortColumn
SET ROWCOUNT :pageSize
SELECT ... FROM Table WHERE SortColumn >= #Sort ORDER BY SortColumn
";
$dbh->prepare($query);
$sth->bindParam(':startRow',0, PDO::PARAM_INT);
$sth->bindParam(':pageSize',10, PDO::PARAM_INT);
$sth->execute();
How can I run multiple select statements in the same query in PDO? My SQL statement works fine when I run it in phpMyAdmin? Code is below:
$sql = 'SELECT DISTINCT apartment.apartmentName,
apartment.apartmentID
FROM apartment_information apartment,
apartment_ratings ratings,
apartment_floorplans floorplan,
user_user user
WHERE user.preferred_zip = :zip
AND floorplan.apartmentID = apartment.apartmentID
AND floorplan.apartmentID = (SELECT apartmentID
FROM apartment_floorplans
WHERE monthlyPrice < :monthlyPrice
AND apartmentNumBedrooms = :apartmentNumBedrooms
AND apartmentNumBathrooms = :apartmentNumBathrooms)';
try{
echo $sql;
$stmt = $this->_db->prepare($sql);
$stmt->bindParam(":zip", $this->_zip, PDO::PARAM_STR);
$stmt->bindParam(":monthlyPrice", $this->_apartmentFloorPlans['Price'], PDO::PARAM_STR);
$stmt->bindParam(":apartmentNumBedrooms", $this->_apartmentFloorPlans['Bedrooms'], PDO::PARAM_STR);
$stmt->bindParam(":apartmentNumBathrooms", $this->_apartmentFloorPlans['Bathrooms'], PDO::PARAM_STR);
}
$stmt->execute();
I've tried following the PHP.net instructions for doing SELECT queries but I am not sure the best way to go about doing this.
I would like to use a parameterized SELECT query, if possible, to return the ID in a table where the name field matches the parameter. This should return one ID because it will be unique.
I would then like to use that ID for an INSERT into another table, so I will need to determine if it was successful or not.
I also read that you can prepare the queries for reuse but I wasn't sure how this helps.
You select data like this:
$db = new PDO("...");
$statement = $db->prepare("select id from some_table where name = :name");
$statement->execute(array(':name' => "Jimbo"));
$row = $statement->fetch(); // Use fetchAll() if you want all results, or just iterate over the statement, since it implements Iterator
You insert in the same way:
$statement = $db->prepare("insert into some_other_table (some_id) values (:some_id)");
$statement->execute(array(':some_id' => $row['id']));
I recommend that you configure PDO to throw exceptions upon error. You would then get a PDOException if any of the queries fail - No need to check explicitly. To turn on exceptions, call this just after you've created the $db object:
$db = new PDO("...");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
I've been working with PDO lately and the answer above is completely right, but I just wanted to document that the following works as well.
$nametosearch = "Tobias";
$conn = new PDO("server", "username", "password");
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sth = $conn->prepare("SELECT `id` from `tablename` WHERE `name` = :name");
$sth->bindParam(':name', $nametosearch);
// Or sth->bindParam(':name', $_POST['namefromform']); depending on application
$sth->execute();
You can use the bindParam or bindValue methods to help prepare your statement.
It makes things more clear on first sight instead of doing $check->execute(array(':name' => $name)); Especially if you are binding multiple values/variables.
Check the clear, easy to read example below:
$q = $db->prepare("SELECT id FROM table WHERE forename = :forename and surname = :surname LIMIT 1");
$q->bindValue(':forename', 'Joe');
$q->bindValue(':surname', 'Bloggs');
$q->execute();
if ($q->rowCount() > 0){
$check = $q->fetch(PDO::FETCH_ASSOC);
$row_id = $check['id'];
// do something
}
If you are expecting multiple rows remove the LIMIT 1 and change the fetch method into fetchAll:
$q = $db->prepare("SELECT id FROM table WHERE forename = :forename and surname = :surname");// removed limit 1
$q->bindValue(':forename', 'Joe');
$q->bindValue(':surname', 'Bloggs');
$q->execute();
if ($q->rowCount() > 0){
$check = $q->fetchAll(PDO::FETCH_ASSOC);
//$check will now hold an array of returned rows.
//let's say we need the second result, i.e. index of 1
$row_id = $check[1]['id'];
// do something
}
A litle bit complete answer is here with all ready for use:
$sql = "SELECT `username` FROM `users` WHERE `id` = :id";
$q = $dbh->prepare($sql);
$q->execute(array(':id' => "4"));
$done= $q->fetch();
echo $done[0];
Here $dbh is PDO db connecter, and based on id from table users we've get the username using fetch();
I hope this help someone, Enjoy!
Method 1:USE PDO query method
$stmt = $db->query('SELECT id FROM Employee where name ="'.$name.'"');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
Getting Row Count
$stmt = $db->query('SELECT id FROM Employee where name ="'.$name.'"');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';
Method 2: Statements With Parameters
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=?");
$stmt->execute(array($name));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Method 3:Bind parameters
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=?");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
**bind with named parameters**
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=:name");
$stmt->bindValue(':name', $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
or
$stmt = $db->prepare("SELECT id FROM Employee WHERE name=:name");
$stmt->execute(array(':name' => $name));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Want to know more look at this link
if you are using inline coding in single page and not using oops than go with this full example, it will sure help
//connect to the db
$dbh = new PDO('mysql:host=localhost;dbname=mydb', dbuser, dbpw);
//build the query
$query="SELECT field1, field2
FROM ubertable
WHERE field1 > 6969";
//execute the query
$data = $dbh->query($query);
//convert result resource to array
$result = $data->fetchAll(PDO::FETCH_ASSOC);
//view the entire array (for testing)
print_r($result);
//display array elements
foreach($result as $output) {
echo output[field1] . " " . output[field1] . "<br />";
}