Preg_replace with a query to database - php

I know "preg_replace" function but not how to use a query inside it. For instance I'm able to convert __ into <em>:
$text = preg_replace('/__(.+?)__/s', '<em>$1</em>', $text);
I am looking for something more powerful.
I would like to replace some pre-formatted text (i.e. [TTT]112233[/TTT]) into another text which is the result of a query (i.e. echo "$text2"; ).
The variable $text2 is the result of a query like "SELECT * FROM table WHERE id=112233";
Is there an embedded php function that do this? Many thanks, Fabio

Here's a way to do this. Probably not the most efficient, but it's a way. It's based in preg_replace_callback
$line = preg_replace_callback(
'|[TTT](\d+)[/TTT]|',
function ($matches) use ($dbConnection) {
$q = "SELECT textColumn FROM table WHERE id=? LIMIT 1";
$stmt = mysqli_prepare($dbConnection,$q);
mysqli_bind_param("i",$matches[1]);
mysqli_execute($stmt);
mysqli_bind_result($result);
mysqli_fetch($stmt);
return "[TTT]$result[/TTT]";
},
$line
);
Note this assumes mysqli but your method may differ.

Related

preg_replace - don't replace in already replaced parts

Given SQL-query with placeholders:
SELECT * FROM table WHERE `a`=? AND `b`=?
and query parameters ['aaa', 'bbb'], i would like to replace ?-placeholders with corresponding params. So, I do it like this:
$sql = preg_replace(array_fill(0, count($params), '#\?#'), $params, $sql, 1);
(we do not concentrate on mysql-escaping, quoting etc. in this question).
Everything works fine and I get
SELECT * FROM table WHERE `a`=aaa AND `b`=bbb
But if our first parameter looks like this: "?aa", everything fails:
SELECT * FROM table WHERE `a`=bbba AND `b`=?
obviously, first replacement pass changes "a=?" into "a=?aa", and second pass changes this (just inserted) question mark into "bbb".
The question is: how can I bypass this confusing preg_replace behaviour?
You can use preg_replace_callback to use one item from $params at a time for each replacement.
$sql = 'SELECT * FROM table WHERE `a`=? AND `b`=?';
var_dump('Original: ' . $sql);
$params=['aaa','bbb'];
$sql = preg_replace_callback("/\\?/",function($m) use (&$params) {
return array_shift($params);
}, $sql);
var_dump('Result: ' . $sql);
Let me know
I would not do this with preg_replace or str_replace. I would use preg_split so empty returns can be removed (If explode had empty removal option I'd use that). For there iterate over the return and add in values. You also can quote the values with this. I presume the purpose of this is for debugging parameterized queries.
$sql = 'SELECT * FROM table WHERE `a`=? AND `b`=?';
$v = array('1?1', "222");
$e = preg_split('/\?/', $sql, NULL, PREG_SPLIT_NO_EMPTY);
$c = '';
foreach($e as $k => $v1){
$c .= $v1 . "'" . $v[$k] ."'";
}
error_log($c);
Then your error log will have:
SELECT * FROM table WHERE `a`='1?1' AND `b`='222'

PHP Search Using Multiple Words

I am trying to create a search function where a user can input two words into a text field and it will split the words and construct a MySQL query.
This is what I have so far.
$search = mysql_real_escape_string( $_POST['text_field']);
$search = explode(" ", $search);
foreach($search as $word)
{
$where = "";
$where .= "product_code LIKE '%". $word ."%'";
$where .= "OR description LIKE '%". $word ."%'";
$query = "SELECT * FROM customers WHERE $where";
$result = mysql_query($query) or die();
if(mysql_num_rows($result))
{
while($row = mysql_fetch_assoc($result))
{
$customer['value'] = $row['id'];
$customer['label'] = "{$row['id']}, {$row['name']} {$row['age']}";
$matches[] = $customer;
}
}
else
{
$customer['value'] = "";
$customer['label'] = "No matches found.";
$matches[] = $customer;
}
}
$matches = array_slice($matches, 0, 5); //return only 5 results
It constructs and runs the query, but returns funny results.
Any help would be appreciated.
MySQL has something called LIMIT, so you last row would be needless.
Use Full-Text-Search for this: http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html - It's faster and more elegant
If your database is on MyISAM table format you could do a Fulltext search on the columns you are interested as Sn0opy mentioned already
Personally I believe that when it comes to mySQL if you actually want to create a great search engine use Sphinx (http://sphinxsearch.com/) or Solr (http://lucene.apache.org/solr/)
There may be a learning curve on both of them, but the results are professional.
Any chance of anything more specific than "funny results"? Off the cuff there are several possibilities but it really depends upon the results that are being returned. My PHP is a bit rusty so I will apologize up front if my brain throws in some java rules instead, but at first blush...
Name the array something other than $search. It probably isn't the problem, but it looks odd to have the array created by explode() carry the name of the string being exploded. Try something like $searched = explode(" ", $search); and then use $searched in the subsequent foreach() loop.
What if the user only puts in one search term? If there is no space in $text_field then explode will return an empty array, which should thoroughly jack up your query. You should at least verify that there is a space in $text_field before exploding $search. Likewise, what if the user enters two search terms, but one of the terms is two words separated by a space? Again you are going to get "funny results" because you will get results that you don't want along with duplicated results as the query extends itself to both of the words in a term individually.
Without knowing more of what you mean by "funny results" it is really difficult to trouble shoot this one.

Passing a db_query as a parameter

I am trying to pass a db_query as a parameter in a function, but I am not getting what I want.
For example
function some_function(){
$query = "SELECT text FROM my_table";
$result = db_query( $query );
$text = other_function( $result );
echo $text;
}
function other_function( &$result ){
$array = db_fetch_array( $result );
return $array['text'];
}
I have verified that the query works and that this works if I don't run it through another function. Any ideas of what I am doing wrong? Any ideas of a better way to do this? I would still like to be able to use a separate function to fetch the arrays from my db_query if possible.
remove the &. It seems unnecessary here. Also, I would use objects for this sort of job, this way you can simply use $this->result or its similarities.

How to select results from a MySQL DB using Strpos instead of a While statement?

I have been using the PHP function strpos to find results containing the characters of a string from a DB:
User Types: Hel
Results: Hello, Hell, Helli, Hella
I have it basically query the entire table:
$result = mysql_query("SELECT * FROM Events");
And then ran a while statement to see which of the results contain the characters of the input:
while($row = mysql_fetch_array($result))
{
$pos = strpos($row['Title'], $q);
if ($pos === false) {
} else {
echo $row['Title'];
}
}
And to find the number of results, I was using:
$n = $n++
Inside of the while statement.
I know you can use:
$num_rows = mysql_num_rows($result);
To find the number of results if you are only selecting those values from the database, but do I have to use this while statement to find the number of results that match the strpos function? Or can I put the strpos in to the Select From query?
Any help is greatly appreciated,
Taylor
This seems highly inefficient. Why wouldn't you simply let the database do the searching for you?
$result = mysql_query("SELECT * FROM Events WHERE Title LIKE '" . addslashes($q) . "%'");
Then just loop through the results.
You could update your SQL to something like
SELECT *
FROM Events
WHERE Title LIKE '{your_string}%'
Make sure to filter for sql injection though.
You can use the LIKE statement:
SELECT * FROM Events WHERE field1 LIKE '%something%'
Where the special % characters say "Anything of any length"; so we're searching for something (or nothing), then the string, then something (or nothing.) For example, searching for %f% will match foo, off, and affirmative.
Just as general advice, I recommend that you use php's MySQLi class; it's an improved version (hence the i), and provides prepared statements, so you won't have to worry too much about SQL injections.

MySql : can i query " WHERE '$str' LIKE %table.col% "?

Basically i want to add wildcards to the the col value when searching...
Usually I do this the other way around like this:
WHERE cakes.cake_name LIKE '%$cake_search%'
however now i want it to match the inverse:
the user searches for 'treacle
sponge', i want this to match a row
where the cake_name column =
'sponge'.
is this possible?
WHERE '$cake_search' LIKE concat('%',cakes.cake_name, '%')
should work. It will need a full table scan but so will the inverse query. Have you looked into full text search for MySQL? It will likely make this sort of query more efficient.
Why not using MATCH?
MATCH(`cake_name`) AGAINST ('treacle sponge')
You would have to split the user supplied input on the space character and dynamically construct your query to check the column for those values:
$input = "treacle sponge";
$input_words = explode(' ', $input);
$sql_where = "WHERE cakes.cake_name IN('" . implode("','", $input_words) . "')"; // generates: WHERE cakes.cake_name IN('treacle','sponge')
In order to prevent SQL-Injection, I suggest using prepared statements.
$prepStmt = $conn->prepare('SELECT ... WHERE cakes.cake_name LIKE :cake_search
');
if($prepStmt->execute(array('cake_search'=>"%$cake_search%"))) {
...
}
Or, using full text search:
$prepStmt = $conn->prepare('SELECT ... WHERE MATCH (`cake_name`) AGAINST (:cake_search IN BOOLEAN MODE)');
if($prepStmt->execute(array('cake_search'=>$cake_search_words))) {
...
}
See JSON specialchars JSON php 5.2.13 for a complete example.. ;)

Categories