Is it possible to insert the same value more than once into an escaped string? ie
$wpdb->prepare("SELECT * FROM table WHERE (column1 = %s || column2 = %s || column3 = %s) AND this = $s", $search_terms,$that");
If not, does anyone have a good alternative for a condition builder. The SQL is run more than once, on a selection of tables. Some tables have more columns to be searched than others, so I created a condition builder. But now I'm trying to escape the values to prevent SQL injects.
$conditions = "";
$query_seperator = " || ";
$i = 0;
foreach($table['fields'] as $field){
if ($i < ($field_count-1)){
$conditions = $conditions . $field . " LIKE %s" . $query_seperator;
} else {
$conditions = $conditions . $field . " LIKE %s";
}
$i++;
}
$wpdb->prepare("SELECT * FROM table WHERE ($conditions) AND this = $s", $search_terms,$that");
Your query seems to be equivalent to
$wpdb->prepare("SELECT * FROM table WHERE %s IN (column1,column2,column3) AND this = $s", $search_terms,$that");
Related
Currently, in my search bar, I'm able to find the name of a city if I type it in exactly the way it has been put into the database. For example: Nuits-Saint-Georges or Durham, NC.
I would like for my users to be able to type in Nuits Saint Georges or Durham NC.
The Cities are located in "location".
function Wo_GetAllJobs($filter_data = array()) {
global $wo, $sqlConnect;
$data = array();
$query_one = " SELECT * FROM " . T_JOB . " WHERE status = '1'";
if (!empty($filter_data['c_id'])) {
$category = $filter_data['c_id'];
$query_one .= " AND `category` = '{$category}'";
}
if (!empty($filter_data['after_id'])) {
if (is_numeric($filter_data['after_id'])) {
$after_id = Wo_Secure($filter_data['after_id']);
$query_one .= " AND `id` < '{$after_id}' AND `id` <> $after_id";
}
}
if (!empty($filter_data['keyword'])) {
$keyword = Wo_Secure($filter_data['keyword']);
$query_one .= " AND (`title` LIKE '%{$keyword}%' OR `location` LIKE
'%{$keyword}%') ";
}
if (!empty($filter_data['user_id'])) {
$user_id = Wo_Secure($filter_data['user_id']);
$query_one .= " AND `user_id` = '{$user_id}'";
}
if (!empty($filter_data['type'])) {
$type = Wo_Secure($filter_data['type']);
$query_one .= " AND `job_type` = '{$type}'";
}
if (!empty($filter_data['length'])) {
$user_lat = $wo['user']['lat'];
$user_lng = $wo['user']['lng'];
$unit = 6371;
$query_one = " AND status = '1'";
$distance = Wo_Secure($filter_data['length']);
if (!empty($filter_data['c_id'])) {
$category = $filter_data['c_id'];
$query_one .= " AND `category` = '{$category}'";
}
if (!empty($filter_data['after_id'])) {
if (is_numeric($filter_data['after_id'])) {
$after_id = Wo_Secure($filter_data['after_id']);
$query_one .= " AND `id` < '{$after_id}' AND `id` <> $after_id";
}
}
if (!empty($filter_data['keyword'])) {
$keyword = Wo_Secure($filter_data['keyword']);
$query_one .= " AND (`title` LIKE '%{$keyword}%' OR `location` LIKE
'%{$keyword}%') ";
}
if (!empty($filter_data['user_id'])) {
$user_id = Wo_Secure($filter_data['user_id']);
$query_one .= " AND `user_id` = '{$user_id}'";
}
if (!empty($filter_data['type'])) {
$type = Wo_Secure($filter_data['type']);
$query_one .= " AND `job_type` = '{$type}'";
}
Split your keyword by spaces then implode them by %
//TODO query_one
//$query_one .= " AND (`title` LIKE ? OR `location` LIKE ?) ";
$stmt = $mysqli->prepare($query_one);
$keyWord = "%" . implode("%", explode(" ", $keyword)) . "%";
$stmt->bind_param("s", $keyWord));
$stmt->bind_param("s", $keyWord));
$stmt->execute();
Remember that prepared statements is a MUST and easy to switch to
note:
using % at the beginning of the keyword will make the optimizer not be able to use the index on that column, if any exists, so if your data size is big and you started to encounter performance issues, you can go to Full Text Search (FTS) check this
Don't worry about case sensitivity comparisons on MySQL
And Regarding the case of the comparison that MySQL will perform, I will quote from the manual "Case Sensitivity in String Searches"
For nonbinary strings (CHAR, VARCHAR, TEXT), string searches use the
collation of the comparison operands. For binary strings (BINARY,
VARBINARY, BLOB), comparisons use the numeric values of the bytes in
the operands; this means that for alphabetic characters, comparisons
will be case-sensitive.
..
The default character set and collation are utf8mb4 and utf8mb4_0900_ai_ci, so nonbinary string comparisons are case insensitive by default.
This is how I ended up solving this issue.
if (!empty($filter_data['keyword'])) {
$keyword = $filter_data['keyword'];
$keywordSearch = Wo_Secure(str_replace(',','',str_replace('-','',str_replace('.','',str_replace(' ', "", $keyword)))));
$keyword = Wo_Secure($keyword);
$query_one .= " AND (`title` LIKE '%{$keyword}%' OR REPLACE(REPLACE(REPLACE(REPLACE(`location`,' ',''),'-',''),'.',''),',','')LIKE '%{$keywordSearch}%') ";
}
I need to set up a SQL query with multiple parameters that are being pulled from the URL. So far I can only get it to work with the there is only one item in the URL.
My default query to pull in all the content
$sql = "SELECT ";
$sql .= "* ";
$sql .= "FROM ";
$sql .= "cms_site_content ";
$sql .= "WHERE ";
$sql .= "1";
I then check if anything was passed through the URL and retrieve it.
if (isset($_GET["d"])) {
$d=$_GET["d"];
Inside the if statement, I break the values passed as "d" into separate items
$newD = explode(',',$d);
$countD = count($newD);
foreach($newD as $discipline) {
if ($countD == 1) {
$sql .= " AND";
$sql .= " discipline='".$discipline."'";
}
My problem is getting the SQL to work if there is more than one discipline value. It should read something like this:
SELECT * FROM cms_site_content WHERE 1 AND discipline="value"
however if there's more than one discipline value, it should read:
SELECT * FROM cms_site_content WHERE 1 AND discipline="value OR discipline="value2" OR discipline="value3"
Is there a more efficient way to write this? I can't figure out how to insert the OR into the foreach statement.
Save all discipline values in an array;
$discipline_arr = array();
foreach($newD as $discipline) {
$discipline_arr[] = $discipline;
// by the way, don't forget to escape for sql injection
// mysql_escape_string is the depracated one, u can use that if u have no
// other choice
}
Then in your sql, add them as discipline in ('value1','value2', 'etc ...') condition (that is for strings, for numeric types it would be like discipline in (1,2,3,4, etc)
$sql = " SELECT * FROM cms_site_content WHERE 1 " .
(empty($discipline_arr) ? "" : "and
discipline in ('". implode("','" , $discipline_arr). "') ") ;
Link to escaping
http://tr1.php.net/manual/en/function.mysql-escape-string.php
Assuming the rest of your query is in tact. Simply store all of your discipline values in an array as follows, then feed the $discipline_string to your $sql query:
$discipline_ary = array('option1', 'option2', 'option3');
$discipline_string = "";
for($i=0; $i < count($discipline_ary); $i++){
$discipline_string .= " discipline = '" . $discipline[$i] . "' ";
if($i+1 == count($discipline_ary)){
break;
}else{
$discipline_string .= " OR "
}
}
I'm new to PHP, and I do not it's syntax and principles very well.
I have such code:
function exportFromTransbase($table_name) {
//$odbc_query = "SELECT * FROM " . $table_name. " WHERE ((CDS_CTM subrange(248 cast integer) = 1) AND (CDS_LNG_ID = 16))";
$odbc_query = "SELECT * FROM " . $table_name. "";
$data = odbc_exec($this->odbc_id, $odbc_query);
odbc_longreadlen($data, 10485760);
$oufile=fopen($table_name.".sql", 'w') or die("error writing file");
$q1='INSERT INTO `' . substr($table_name, 4) . '` VALUES';
fwrite($oufile, $q1);
while($row = odbc_fetch_array($data))
{
foreach($row as $key => $value) {
$keys[] = "`" . $key . "`";
if ($value == ""){
$value = 'NULL';
$values[] = "" . mysql_real_escape_string($value) . "";
}
else{
$values[] = "'" . mysql_real_escape_string($value) . "'";
}
//echo "\n \n ololo ".$value;
}
$mysql_query = "\n (".implode(",", $values).")," ;
fwrite($oufile, $mysql_query);
//mysql_query($mysql_query);
set_time_limit(0);
unset($keys);
unset($values);
unset($row);
}
$stat = fstat($oufile);
ftruncate($oufile, $stat['size']-1);
fseek($oufile, 0, SEEK_END);
fwrite($oufile, ";".$r);
//} while ($r < 5 );
fclose($oufile);
if ($mysql_query){
print "Ýêñïîðò äàííûõ èç òàáëèöû " . $table_name . " çàâåðøåí!";
//strtolower(substr($table_name, 4))
}
}
what and where i need to custom, so that i export all table fields except one, for example called Size, i must insert in db is this field nulls....
Also if it is easy, how to split my sql query in batches of 5000 rows? so insert (5000 rows) then insert another 5000....
But first i need to export all fields, except one...
To the best of my knowledge, it can't be possible.
You can use simply:
SELECT field1, field2, field3, field4 FROM table
See Select all columns except one in MySQL?
And if you have more fields in your table then you can use * only.
At the time of insert you can make a condition which ignores the field which you don't want in new table.
Can you use
"select * from {table} where {sth} != {condition}"
Then you can fetch all data except one. The one is excrpted follow your condition.
Meanwhile,if you want to insert by 5000, you can read 5000 lines one time and insert into.
In my script below, the user inputs a form and rows are returned from a MYSQL table if rows are similar to inputted by the user. I am building a search engine and everything is based on rank. But I want to be able to adjust the code below to see how many times the word 'iPad' for example comes up with the row fields, which are 'title', 'description', 'keywords' and 'link'. If so, I want that row to return higher than say a row that has a higher id, but only mentions iPad once in all of the fields combined.
My code is below:
Terms together query:
$query = " SELECT * FROM scan WHERE ";
$terms = array_map('mysql_real_escape_string', $terms);
$i = 0;
foreach ($terms as $each) {
if ($i++ !== 0){
$query .= " AND ";
}
$query .= "title LIKE '%{$each}%' OR link LIKE '%{$each}%' OR keywords LIKE '%{$each}%' OR description LIKE '%{$each}%' ";
}
$query = mysql_query($query) or die('MySQL Query Error: ' . mysql_error( $connect ));
echo '<p class="time">Qlick showed your results in ' . number_format($secs,2) . ' seconds.</p>';
$numrows = mysql_num_rows($query);
if ($numrows > 0) {
while ($row = mysql_fetch_assoc($query)) {
$id = $row['id'];
$title = $row['title'];
$description = $row['description'];
$keywords = $row['keywords'];
$link = $row['link'];
$rank = $row['rank'];
Seperate Terms Query
$query = " SELECT * FROM scan WHERE ";
$terms = array_map('mysql_real_escape_string', $terms);
$i = 0;
foreach ($terms as $each) {
if ($i++ !== 0){
$query .= " OR ";
}
$query .= "title LIKE '%{$each}%' OR link LIKE '%{$each}%' OR keywords LIKE '%{$each}%' OR description LIKE '%{$each}%' ";
}
// Don't append the ORDER BY until after the loop
$query = mysql_query($query) or die('MySQL Query Error: ' . mysql_error( $connect ));
$numrows = mysql_num_rows($query);
if ($numrows > 0) {
while ($row = mysql_fetch_assoc($query)) {
$id = $row['id'];
$title = $row['title'];
$description = $row['description'];
$keywords = $row['keywords'];
$link = $row['link'];
$rank = $row['rank'];
I'd try to do this using an auxiliary field on which to run a FULLTEXT query, in which you would save all textual data:
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
The alternative is to run the filtering in MySQL and the ranking in PHP. You might squeeze some performance by running a single LIKE on the concatenated field.
By the way, your code above lacks parentheses in the LIKE, so that the results won't be correct: you mustn't ask WHERE field1 LIKE 'x' OR field2 LIKE 'x' AND field1 LIKE 'y' OR..., you must state WHERE (field1 LIKE 'x' OR field2 LIKE 'x') AND (field1 LIKE 'y' OR...).
// Here we search for ALL terms (all must be present at least once)
// use ' OR ' to ask that at least one term must be present once.
$where = array();
foreach($terms as $term)
$where[] = "( CONCAT(title,'|',link,'|',keywords) LIKE '%{$term}%')";
$query .= ' WHERE ' . '('.implode(' AND ', $where).')';
Now in the OR case you could do a simple ranking on the number of matched terms (with AND the number is always the total number of terms):
$select_fields[] '(' . implode ('+', $where) . ') AS ranking';
Otherwise in SQL you would need recourse to a really ugly hack:
(LENGTH(
REPLACE(CONCAT(title,'|',link,'|',keywords),'{$term}','')
) - LENGTH(CONCAT(title,'|',link,'|',keywords)))/LENGTH('{$term}');
This above calculates the difference between the total length of the text where the search is to be done and the total length of the same text, with search string removed. The difference is of course proportional to how many times the search string is there: if the string is 8 characters long, a difference of 32 would mean that it is present four times. Dividing the length difference by the length of the term, we obtain the number of hits.
The problem is that for several terms you have to complicate the query enormously, and it might be really expensive to run:
$select_fields = array('*');
$where = array();
$rank = array();
foreach($terms as $term)
{
// assume $term is NOT QUOTED
$search = mysql_real_escape_string($term);
$concat = "CONCAT(title,'|',link,'|',keywords)";
$where[] = "(${concat} LIKE '%{$search}%')";
$rank[] = "(LENGTH(REPLACE(${concat},'{$search}',''))
- LENGTH(${concat}))/LENGTH('{$search}')";
}
$select_fields[] = "(".implode(",", $rank).") AS ranking";
$query .= "SELECT " . implode(',', $select_fields)
. ' FROM scan WHERE (' . implode(' AND ', $where) . ')';
I am writing a code, where I have to produce a query with many OR statements, and I think there is a more comfortable way to this than:
foreach ($plz as &$value) {
if (empty($i)) {
$query = "WHERE plz='$value'";
} else {
$query = "$query OR plz='$value'";
}
$i++;
}
$sql = mysql_query("SELECT * FROM table $query");
while ($data = mysql_fetch_array($sql)) {
//do something
}
If you have multiple values a column may take, just connect them using the IN operator:
Instead of writing
... WHERE col=1 OR col=2 OR col=3
just write
... WHERE col IN (1,2,3)
To collect all entries in PHP, use an array and implode() later on:
// collecting values
$vals = array();
$vals[] = 1;
$vals[] = 2;
// ...
// add them to your query
$query .= ' WHERE col IN ( ' . implode( ',', $vals ) . ')';
// execute the query ...
In case your values are not integer, but need to be enclosed in apostrophes within the query, insert them that way into the array in the first place:
$vals[] = "'my string value'";
You're looking for ;
SELECT * FROM table WHERE plz in ('value1', 'value2', 'value3')
Be aware of SQL injections...
If the column plz is INT type, and all $plz are also integers, then:
$query = 'WHERE plz IN( ' . implode(',', $plz) . ')';
would work. Otherwise, trying this might work(not tested):
$query = 'WHERE plz IN( \'' . implode("','", $plz) . '\')';