preg_replace_callback with array - php

I recently updated my site to PHP 5.6, and since doing that, I started getting errors with the e modifier.
Here is the function causing the issue:
function blockPrepareDisplay() {
static $search = array('/(.)#(.)/se');
static $replace = array('"&#" .sprintf("%03d", ord("\\1")) .";#&#" .sprintf("%03d", ord("\\2")) . ";";');
$resarray = array();
foreach (func_get_args() as $var) {
$var = htmlspecialchars($var, ENT_QUOTES);// Prepare var
$var = preg_replace($search, $replace, $var);
$var = preg_replace('/&#/', '&#', $var);
$var = str_replace(" "," ",$var);
$var = str_replace("&","&",$var);
$resarray[] = $var;// Add to array
}
if (func_num_args() == 1) {// Return vars
return $resarray[0];
} else {
return $resarray;
}
}
I understand that the line static $search = array('/(.)#(.)/se'); is the line with the e modifier and I know that its deprecated. A friend explained that to me, and explained that I wound need to replace the preg_replace with a preg_replace_callback. I have looked over at php.net and all over here, but I think it made me more confuesd than ever.
I have tried for a couple of weeks now many different things and I got one to stop spitting the error, but I am positive that its wrong, and I prefer it to be right than wrong. I did this in replacement of the preg_replace
$var = preg_replace_callback(
$search,
function($replace){
foreach($replace as $replaces){
return $replaces;
}
},
$var
);
Instead of the $var = preg_replace($search, $replace, $var);.
I also did remove the e modifier. Can anyone point out my mistake and give an example of how I should have this to be right?

The argument of the callback function is the array of matching groups.
I don't understand why you are using an array for the search and the replacement parts, I'd do:
$var = "abc#def.org";
$var = preg_replace_callback(
'/(.)#(.)/',
function($match) {
return sprintf("&#%03d;#&#%03d;", ord($match[1]), ord($match[2]));
},
$var
);
echo $var,"\n";
Output:
abc#def.org

Related

Search Tags in Codeigniter

Hello everyone the search is not working. For example the tags contain Php, Ajax, HTML 5 when you search Php or Ajax there is a result but if you search two words or more such as HTML 5 there is no result.
my model Codes:
public function getTagsMatch($limit=null, $tags, $offset=null) {
$match = $tags;
$this->db->from('threads');
$this->db->where('status', 1);
$search_query_values = explode(' ', $match);
$counter = 0;
foreach ($search_query_values as $key => $value) {
if ($counter == 0) {
$this->db->like('tags', $value);
}
$counter++;
}
$this->db->order_by('pin_post', 'DESC');
$this->db->order_by('id', 'DESC');
$this->db->limit($limit);
$this->db->offset($offset);
$query = $this->db->get();
return $query->result_array();
}
Well...
$search_query_values = explode(' ', $match);
This line takes in query values and "explodes" the string using spaces. So if you input "HTML 5", it will actually search for tags like "HTML" or "5". Consider using a different character for exploding.
For example:
$search_query_values = explode(',', $match);
And the function call would be something like this:
getTagsMatch(NULL, 'Ajax,HTML 5,PHP', NULL);
A few more notes:
Default parameters should be at the end of an argument list (function foo(bar0, bar1=0, bar2='') { ... }, not randomly placed).
Consider using less variables. There is absolutely no reason to have $tags, $match and $search_query_values - one is enough. You might consider using 3 variables a semantic advantage, but it actually makes your code more difficult to read.
The problem of this was on my controller because. I customize the tags but the fact is Im having a trouble how to explain this since Im not good in explaining such thing. I will just post some of the codes with some explanation.
My tags search will base on what is the tags slug for example website.com/tags/html-5
so my controller codes:
public function tags($tags) {
$tag = search_title($tags);
$data['result'] = $this->topic_model->getTagsMatch($tag);
}
and my search_title function code:
function search_title($str, $separator = '&nbsp') {
$str = ucwords(strtolower($str));
foreach (array('-', '\'') as $delimiter) {
if (strpos($str, $delimiter)!==false)
{
$str =implode($delimiter, array_map('ucfirst', explode($delimiter, $str)));
}
}
$str = str_replace('-','&nbsp',$str);
$str = str_replace('%20','&nbsp',$str);
$str = str_replace('%26','&',$str);
$str = str_replace('%27','&nbsp',$str);
$str = str_replace('%28','&nbsp',$str);
$str = str_replace('%29','&nbsp',$str);
return trim(stripslashes($str));
}
the problem of it is on this line
$data['result'] = $this->topic_model->getTagsMatch($tag);
so I change the $tag to str_replace("-"," ",$tags)

PHP Replacing Character Inside String With Variable

In few words, I am trying to replace all the "?" with the value inside a variable and it doesn't work. Please help.
$string = "? are red ? are blue";
$count = 1;
update_query($string, array($v = 'violets', $r = 'roses'));
function update_query($string, $values){
foreach ( $values as $val ){
str_replace('?', $val, $string, $count);
}
echo $string;
}
The output I am getting is: ? are red ? are blue
Frustrated by people not paying attention, I am compelled to answer the question properly.
str_replace will replace ALL instances of the search string. So after violets, there will be nothing left for roses to replace.
Sadly str_replace does not come with a limit parameter, but preg_replace does. But you can actually do better still with preg_replace_callback, like so:
function update_query($string, $values){
$result = preg_replace_callback('/\?/', function($_) use (&$values) {
return array_shift($values);
}, $string);
echo $string;
}
You forgot to set it equal to your variable.
$string = str_replace('?', $val, $string, $count);
You probably want to capture the return from str_replace in a new string and echo it for each replacement, and pass $count by reference.
foreach ( $values as $val ){
$newString = str_replace('?', $val, $string, &$count);
echo $newString;
}
This is the best and cleanest way to do it
<?php
$string = "? are red ? are blue";
$string = str_replace('?','%s', $string);
$data = array('violets','roses');
$string = vsprintf($string, $data);
echo $string;
Your code edited
$string = "? are red ? are blue";
update_query($string, array('violets','roses'));
function update_query($string, $values){
$string = str_replace('?','%s', $string);
$string = vsprintf($string, $values);
echo $string;
}
Ok guys here is the solution from a combination of some good posts.
$string = "? are red ? are blue";
update_query($string, array($v = 'violets', $r = 'roses'));
function update_query($string, $values){
foreach ( $values as $val ){
$string = preg_replace('/\?/', $val, $string, 1);
}
echo $string;
}
As mentioned, preg_replace will allow limiting the amount of matches to update. Thank you all.
You can solve this in two ways:
1) Substitute the question marks with their respective values. There are a hundred ways one could tackle it, but for something like this I prefer just doing it the old-fashioned way: Find the question marks and replace them with the new values one by one. If the values in $arr contain question marks themselves then they will be ignored.
function update_query($str, array $arr) {
$offset = 0;
foreach ($arr as $newVal) {
$mark = strpos($str, '?', $offset);
if ($mark !== false) {
$str = substr($str, 0, $mark).$newVal.substr($str, $mark+1);
$offset = $mark + (strlen($newVal) - 1);
}
}
return $str;
}
$string = "? are red ? are blue";
$vars = array('violets', 'roses');
echo update_query($string, $vars);
2) Or you can make it easy on yourself and use unique identifiers. This makes your code easier to understand, and more predictable and robust.
function update_query($str, array $arr) {
return strtr($str, $arr);
}
echo update_query(':flower1 are red :flower2 are blue', array(
':flower1' => 'violets',
':flower2' => 'roses',
));
You could even just use strtr(), but wrapping it in a function that you can more easily remember (and which makes sense in your code) will also work.
Oh, and if you are planning on using this for creating an SQL query then you should reconsider. Use your database driver's prepared statements instead.

php replacement route system

i need function in PHP for handle replacement something like this.
$pattern = ':foo/anotherString';
$replacement = array(
'foo' => 'HelloMe'
);
bazFunction($pattern, $replacement); // return 'HelloMe/anotherString';
this method used in some frameworks as route patterns. i want to know which function handle that.
this should do (5.3 required because of the closure)
function my_replace($pattern, $replacement) {
// add ':' prefix to every key
$keys = array_map(function($element) {
return ':' . $element;
}, array_keys($replacement));
return str_replace($keys, array_values($replacement), $pattern);
}
You wouldn't need this function if you pass the stuff directly to str_replace
str_replace(array(':foo'), array('HelloMe'), ':foo/anotherString');
$string = "foo/anotherString";
$replacement = array('foo','HelloMe');
$newString = str_replace($replacement[],,$string);
It seems that php got the function for you...
str_replace ( ":foo", "HelloMe" , $pattern )
will give you this output: HelloMe/anotherString

Make PHP variable evaluate as 'plain' text

I have two PHP variables that seem to have the same value, $dynamic which is produced from a function and $test which is just text in single quotes.
When I print their values they're the same, but the $dynamic fails in regex functions.
Is there any way to make a PHP string 'not dynamic' and just plain old text
$test = 'username'; //Evaluates OK
die($test.' '.$dynamic); //Produces: username username
Below is the function, $pattern is the issue. This is actually from an earlier question, but I've since narrowed the issue to the evaluation of $pattern. This also seems to be an issue with other functions besides preg_replace_callback.
public function output() {
if (!file_exists($this->file)) {
return "Error loading template file ($this->file).<br />";
}
$output = file_get_contents($this->file);
foreach ($this->values as $key => $value) {
$tagToReplace = "[#$key]";
$output = str_replace($tagToReplace, $value, $output);
$dynamic = preg_quote($key);
$test = 'username';
$pattern = '%\[if #'.$test.'\](.*?)\[/if\]%'; // produces: %\[if #username\](.*?)\[/if\]%
$output = preg_replace_callback($pattern, array($this, 'if_replace'), $output);
}
return $output;
}
It is possible $dynamic may contain invisible characters. Loop over the string and print the character code of each character (use ord) - and compare that with the result for "username".
var_dump might also give hints as it will show the length of the string as well.

Perl to PHP With s///;

In perl, I can do: 1 while $var =~ s/a/b/;, and it will replace all a with b. In many cases, I would use it more like 1 while $var =~ s/^"(.*)"$/$1/; to remove all pairs of double quotes around a string.
Is there a way to do something similar to this in PHP, without having to do
while (preg_match('/^"(.*)"$/', $var)) {
$var = preg_replace('/^"(.*)"$/', '$1', $var, 1);
}
Because apparently,
while ($var = preg_replace('/^"(.*)"$/', '$1', $var, 1)) { 1; }
doesn't work.
EDIT: The specific situation I'm working in involves replacing values in a string with values from an associative array:
$text = "This is [site_name], home of the [people_type]".
$array = ('site_name' => 'StackOverflow.com', 'people_type' => 'crazy coders');
where I would be doing:
while (preg_match('/\[.*?\]/', $text)) {
$text = preg_replace('/\[(.*?)\]/', '$array[\'$1\']', $text, 1);
}
with the intended output being 'This is StackOverflow.com, home of the crazy coders'
preg_replace('#\[(.*?)\]#e', "\$array['$1']", $text);
In all of the cases, you can get rid of the loop by (e.g.) using the /g global replace option or rewriting the regexp:
$var =~ s/a/b/g;
$var =~ s/^("+)(.*)\1$/$2/;
The same patterns should work in PHP. You can also get rid of the $limit argument to preg_replace:
$text = preg_replace('/\[(.*?)\]/e', '$array[\'$1\']', $text);
Regular expressions can handle their own loops. Looping outside the RE is inefficient, since the RE has to process text it already processed in previous iterations.
Could something like this work?
$var = preg_replace('/^("+)(.*)\1$', '$2', $var, 1);
What does your input data look like?
Because you're checking for double quotes only at the head and tail of the string. If that's accurate, then you don't need to capture a backreference at all. Also, that would make sending 1 as the 4th parameter completely superfluous.
$var = '"foo"';
// This works
echo preg_replace( '/^"(.*)"$/', '$1', $var );
// So does this
echo preg_replace( '/^"|"$/', '', $var );
But if your input data looks different, that would change my answer.
EDIT
Here's my take on your actual data
class VariableExpander
{
protected $source;
public function __construct( array $source )
{
$this->setSource( $source );
}
public function setSource( array $source )
{
$this->source = $source;
}
public function parse( $input )
{
return preg_replace_callback( '/\[([a-z_]+)\]/i', array( $this, 'expand' ), $input );
}
protected function expand( $matches )
{
return isset( $this->source[$matches[1]] )
? $this->source[$matches[1]]
: '';
}
}
$text = "This is [site_name], home of the [people_type]";
$data = array(
'site_name' => 'StackOverflow.com'
, 'people_type' => 'crazy coders'
);
$ve = new VariableExpander( $data );
echo $ve->parse( $text );
The class is just for encapsulation - you could do this in a structured way if you wanted.
Use do-while:
do {
$var = preg_replace('/^"(.*)"$/', "$1", $var, 1, $count);
} while ($count == 1);
Requires at least php-5.1.0 due to its use of $count.
You could also write
do {
$last = $var;
$var = preg_replace('/^"(.*)"$/', "$1", $var);
} while ($last != $var);

Categories