2

I am creating a function that replaces certain parts of a string with predefined constants, for this I have created this function:

<?php

function ReplaceWithPath($string)
{
    $toReplace = ["~~BASEPATH~~" => ABSPATH, "~~LIBPATH~~" => LIBPATH];

    foreach ($toReplace as $replace => $replacement)
    {
        if (preg_match($replace, $string))
            return str_replace($replace, $replacement, $string);
        else
            continue;
    }
    return false;
}

?>

But for some reason, when I use it it does not give me a proper result, but instead boolean false.

I am using the function in my config file as such:

<?php

$cfg_file = str_replace("\\", "/", dirname(__FILE__)) . "/web.config.xml";
$cfg = simplexml_load_file($cfg_file);

define("ABSPATH", $cfg->paths->basepath);

require_once 'library/functions/ReplaceWithString.php';
define("LIBPATH", ReplaceWithPath($cfg->paths->libpath));
var_dump(LIBPATH);

?>

The part of the XML file in question is this:

<paths>
  <basepath>E:/projects/php/site/site/</basepath>
  <libpath>~~BASEPATH~~library/</libpath>
  <classpath>~~LIBPATH~~class/</classpath>
  <traitpath>~~LIBPATH~~trait/</traitpath>
</paths>

I need to be able to change the parts that are ~~BASEPATH~~ with ABSPATH but it just return boolean false.

Edit

After testing, I have found that it is the fact that there are multiple constants in the array ($toReplace) that is causing this not to work. WHY IT DO DIS?!?!?!

New function created:

function ReplacePathPart($path)
{
    $replaced = "";
    $toReplace = array(
        '!!BASEPATH!!'=>ABSPATH, 
        '!!LIBPATH!!'=>LIBPATH
    );

    foreach ($toReplace as $replace => $replacement)
    {
        $replaced = str_replace($replace, $replacement, $path);
    }

    return $replaced;
}

Amended config file:

<?php

$cfg_file = str_replace("\\", "/", dirname(__FILE__)) . "/config/web.config.xml";
$cfg = simplexml_load_file($cfg_file);

define("ABSPATH", $cfg->paths->basepath);
require_once 'library/functions/ReplaceWithString.php';
define("LIBPATH", ReplacePathPart($cfg->paths->libpath));
define("CLASSPATH", ReplacePathPart($cfg->paths->classpath));

print ABSPATH . " |abspath<br />";
print LIBPATH . " |libpath<br />";
print CLASSPATH . " |classpath<br />";

?>

Output:

E:/projects/php/site/site/ |abspath
!!BASEPATH!!library/ |libpath
!!BASEPATH!!library/class/ |classpath

4
  • Doesn't this just work: $replacedResult = str_replace(array_keys($toReplace), array_values($toReplace), $string); ? Commented Dec 7, 2015 at 16:15
  • BTW: In ~~BASEPATH~~, ~ will be seen as delimiter for your preg_match() call and your regex will fail with unescaped delimiters Commented Dec 7, 2015 at 16:17
  • You don't need a loop, str_replace() also can take arrays as argument, as I said just use: $replacedResult = str_replace(array_keys($toReplace), array_values($toReplace), $string); you overthink this way too much.; Now you use $path each source which doesn't change and save it in $replaced, that's why only the last one gets replaced Commented Dec 7, 2015 at 16:40
  • @Rizier123, I got the wrong end of the stick on that one! My bad and can you add as an answer? Commented Dec 7, 2015 at 16:41

1 Answer 1

2

It seems like you are overthinking this way too much. Drinking a cup of coffee(☕) or reading this answer should solve the problem:

First off your original function:

function ReplaceWithPath($string)
{
    $toReplace = ["~~BASEPATH~~" => ABSPATH, "~~LIBPATH~~" => LIBPATH];

    foreach ($toReplace as $replace => $replacement)
    {
        if (preg_match($replace, $string))
            return str_replace($replace, $replacement, $string);
        else
            continue;
    }
    return false;
}

In your preg_match() call ~ will be seen as delimiter for the regex string. So in your strings: ~~BASEPATH~~, ~~LIBPATH~~ you then have unescaped delimiters, which means your regex will fail.

The return statement in your foreach loop would immediately stop the function call and would only replace 1 search => replace element.

Searching for the search strings and looping through the replacement array is unnecessary. Since with str_replace() you already search for the search strings + you can pass arrays to the function:

mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )


Now in your second try you get a bit closer to the solution, but still make some logical mistakes:

function ReplacePathPart($path)
{
    $replaced = "";
    $toReplace = array(
        '!!BASEPATH!!'=>ABSPATH, 
        '!!LIBPATH!!'=>LIBPATH
    );

    foreach ($toReplace as $replace => $replacement)
    {
        $replaced = str_replace($replace, $replacement, $path);
    }

    return $replaced;
}

You still loop through the replacement array and now you use $path as source which will never change and in each iteration you overwrite $replaced with the replaced string. So at the end you end up with only replacing the last search => replace element.


The solution to your problem is simple:

function ReplacePathPart($path)
{
    $toReplace = array(
        '!!BASEPATH!!'=>ABSPATH, 
        '!!LIBPATH!!'=>LIBPATH
    );    

    return str_replace(array_keys($toReplace), array_values($toReplace), $path);

}

As I said str_replace() can take arrays as arguments, so with array_keys($toReplace) you search for your keys(!!BASEPATH!!, !!LIBPATH!!) and replace them with the values(ABSPATH, LIBPATH), which you get with array_values($toReplace).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.