Jump to content

Please Help!!! Find and Replace PHP Code in an Existing File


milton_1223

Recommended Posts

Hi everyone,  :D

 

Lets say i made a mod to an existing scrip and want to implement it automatically. Im trying to make an installation script that would find some php files, open them, search for a specific line of code and replace it with another line in some cases and in some cases just insert some code below that line without replacing anything. Im up to the part of the file opening, but Im Stuck in the search. I can find ONE line of code, but in some cases I need to find a whole block. How can I find a specific block of code, and since im no expert, does the tabs in front of the code matters? I guess they do, but im not sure.

 

Let me show you an example of what im trying to do....

 

The first case is to find a single line of code like this...

$userinfo['ship_country_list'] = getoptionlist('state_country', 'abb', 'name', 'WHERE type=\'' . COUNTRY . '\'', ($userinfo[ship_country] == "") ? $settings[country] : $userinfo[ship_country], 'name');

 

And insert a block of code like this beneath it....

////////////// Start Account Type - Changes Required/////////////
$userinfo['account_type'] = getaccounttype($userinfo[group_in]);
$userinfo['account_type_list'] = getoptionlist('groups', 'id', 'name', 'WHERE visible=\'1\' ', $userinfo[group_in], 'name', 1);
////////////// End Account Type - Changes Required/////////////

 

The second case is to find a block of code like this...

** Notice the tabs in front of the code, since the original script file is formated like that i don´t know how to work arround this.

					while ($field = $DB_site->fetch_assoc($result))
					{
							if ($field['Field'] == 'password') $vars[password] = md5($vars[password]);
							if (isset($vars[$field['Field']])) $query .= " `" . $field['Field'] . "`='" . sf($vars[$field['Field']]) . "',";
					}
					$query .= " `group_in`='" . $settings[defaultgroup] . "'";

 

and replace it with another block of code like this...

////////////// Start Account Type - Changes Required/////////////
while ($field = $DB_site->fetch_assoc($result))
{
    if ($field['Field'] == 'password') $vars[password] = md5($vars[password]);
    if ($field['Field'] == 'username')
    {
        if (isset($vars[$field['Field']])) $query .= " `" . $field['Field'] . "`='" . sf($vars[$field['Field']]) . "'";
    }else{
        if ($field['Field'] == 'group_in')
        {
            if (getoptionlist('groups', 'id', 'name', 'WHERE visible=\'1\' ', "", 'name', 0) == "")
            {
                $query .= ", `" . $field['Field'] . "`='" . $settings[defaultgroup] . "'";
            }else{
                if (isset($vars[$field['Field']])) $query .= ", `" . $field['Field'] . "`='" . sf($vars[$field['Field']]) . "'";
            }
        }else{
            if (isset($vars[$field['Field']])) $query .= ", `" . $field['Field'] . "`='" . sf($vars[$field['Field']]) . "'";
        }
    }
}
////////////// End Account Type - Changes Required/////////////

 

if someone can help me on this or point me in the right direction would be much appreciated...  ;D

preg_match should do the trick. It can find blocks of code over multiple lines. But, I would recommend building all the options into your code, and using your install script to build a config file. Then your code can just check the values of the config to figure out what to do. It's much cleaner in my opinion and allows you to change the options on the fly.

Here is a sample of what revraz is talking about:

 

<?php
  $file = 'code.php';
  $code = file_get_contents($file);
  
  $find = '$userinfo[\'ship_country_list\'] = getoptionlist(\'state_country\', \'abb\', \'name\', \'WHERE type=\\\'\' . COUNTRY . \'\\\'\', ($userinfo[ship_country] == "") ? $settings[country] : $userinfo[ship_country], \'name\');';
  $replace = $find."\n".
            '  ////////////// Start Account Type - Changes Required/////////////'."\n".
            '  $userinfo[\'account_type\'] = getaccounttype($userinfo[group_in]);'."\n".
            '  $userinfo[\'account_type_list\'] = getoptionlist(\'groups\', \'id\', \'name\', \'WHERE visible=\\\'1\\\' \', $userinfo[group_in], \'name\', 1);'."\n".
            '  ////////////// End Account Type - Changes Required/////////////'."\n";
  if($newcode = str_replace($find,$replace,$code)){
    file_put_contents($file,$newcode);
    print "Replaced";
  }else
    print "No Match";
?>

 

<?php
  //Here is a comment
  if('today' == 'tomorrow'){
    rsort($days);
  }
  $userinfo = array();
  $userinfo['ship_country_list'] = getoptionlist('state_country', 'abb', 'name', 'WHERE type=\'' . COUNTRY . '\'', ($userinfo[ship_country] == "") ? $settings[country] : $userinfo[ship_country], 'name');
  print_r($userinfo);
?>

ok this works like a charm when it comes to finding one line and replacing it with one line or a block as you did on the example, but what about finding a block of code and replacing it??? I tried to modify it but couldnt get it to work.

here´s what I did... it was just a simple change to the variable content....

 

  $file = 'code.php';
  $code = file_get_contents($file); 

  $find = '						while ($field = $DB_site->fetch_assoc($result))' . "\n" .
'						{' . "\n" .
'								if ($field[\'Field\'] == \'password\') $vars[password] = md5($vars[password]);' . "\n" .
'								if (isset($vars[$field[\'Field\']])) $query .= \" `\" . $field[\'Field\'] . \"`=\'\" . sf($vars[$field[\'Field\']]) . \"\',\";' . "\n" .
'						}' . "\n" .
'						$query .= \" `group_in`=\'\" . $settings[defaultgroup] . \"\'\";';

  $replace = '  ////////////// Start Account Type - Changes Required/////////////'."\n".
            '  What ever goes here  '."\n".
            '  ////////////// End Account Type - Changes Required/////////////'."\n";
  if($newcode = str_replace($find,$replace,$code)){
    file_put_contents($file,$newcode);
    print "Replaced";
  }else
    print "No Match";

 

I dont get it... am I missing something here... Im sorry, Im practically new at this...

first, let me say again that a config file will probably make this WAY easier

 

second, to get that to match every space and character perfectly is going to be tough. one thing you can do though is mark the start and end with comments (like you do now) and search on the comments. how about something like this:

 

<?php
  function doReplace ( $key, $replacement, $text, $append = false ) {
    $regex = "#(//START\s+{$key}\s+START//\s+)(.+)(//END\s+{$key}\s+END//)#s";
    $replace = '$1'.($append?'$2':'').$replacement.'$3';
    if($newcode = preg_replace($regex,$replace,$text)){
      return $newcode;
    }
    return false;
  }

  $file = 'code.php';
  $code = file_get_contents($file); 

  //Normal Replacement
  $replace = "What ever goes here\n";
  if($newcode = doReplace('Account Type',$replace,$code))
    file_put_contents($file,$newcode);
  else
    die("Failed");

  //Appending
  $replace = "This will be appended instead\n";
  if($newcode = doReplace('Account Type',$replace,$code,true))
    file_put_contents($file,$newcode);
  else
    die("Failed");


  print "DONE";
?>

 

<?php
  //Here is a comment
  if('today' == 'tomorrow'){
    rsort($days);
  }

//START Account Type START//
    while ($field = $DB_site->fetch_assoc($result))
    {
        if ($field['Field'] == 'password') $vars[password] = md5($vars[password]);
        if (isset($vars[$field['Field']])) $query .= " `" . $field['Field'] . "`='" . sf($vars[$field['Field']]) . "',";
    }
    $query .= " `group_in`='" . $settings[defaultgroup] . "'";
//END Account Type END//

  $userinfo = array();
  $userinfo['ship_country_list'] = getoptionlist('state_country', 'abb', 'name', 'WHERE type=\'' . COUNTRY . '\'', ($userinfo[ship_country] == "") ? $settings[country] : $userinfo[ship_country], 'name');
  print_r($userinfo);
?>

I couldn't argree more with you, it would be easier and cleanner that way, the problem is that I won't have access to all the original files (not that I want to) to be able to implement it this way... Im trying to deploy a mod for a shopping cart script that I made myself and want to make it available free for any one who wants it, but the thing is that not every one knows how to change a script and I just want to meke a simple solution for those people... You see, its not viable to implement it this way you are telling me, although it would be much simpler that way... although, there´s... I just had an idea, let me see and ill get back to you latter... Thanks rhodesa you´ve been very helpfull.

Ok, here is the solution I came up with... Althoug it may not be perfect, it works for me, and it may be a start for something far more complex and functiona...

 

First of all forget abot regex and that stuff, Is too complex for me... at least for now, I want to learn that soon but dont have the time now...

 

Here goes... First define my imput and output file, since im replacing its just one.

<?php
$file = "x_file_x.php";

 

Then, i define an array with the lines of code that I want to search for

$search[0] ="\t\t".'$userinfo[\'ship_country_list\'] = getoptionlist(\'state_country\', \'abb\', \'name\', \'WHERE type=\\\'\' . COUNTRY . \'\\\'\', ($userinfo[ship_country] == "") ? $settings[country] : $userinfo[ship_country], \'name\');'."\r\n";
$search[1] ="\t\t".'if ($_POST[\'do\'] == "create" && !$ae->is_errors())'."\r\n";
$search[2] ="\t\t\t\t\t\t".'while ($field = $DB_site->fetch_assoc($result))'."\r\n";
$search[3] ="\t\t\t\t".'return template(\'account_customer_signup.html\', array(\'userinfo\' => $userinfo, \'hide\' => $hide, \'lang\' => $lang[account], \'message\' => array(\'error\' => $ae->display())));'."\r\n";
$search[4] ="\t\t".'if (p($settings[order_min]) != p(0) && p($orderinfo[total], false) < p($settings[order_min], false))'."\r\n";

 

After that define arrays with the replacements codes that Im going to use...

$replace_01[0]="\t\t".'////////////// End Account Type - Changes Required/////////////'."\r\n";
$replace_01[1]="\t\t".'$userinfo[\'account_type_list\'] = getoptionlist(\'groups\', \'id\', \'name\', \'WHERE visible=\\\'1\\\' \', $userinfo[group_in], \'name\', 1);'."\r\n";
$replace_01[2]="\t\t".'$userinfo[\'account_type\'] = getaccounttype($userinfo[group_in]);'."\r\n";
$replace_01[3]="\t\t".'////////////// Start Account Type - Changes Required/////////////'."\r\n";

$replace_02[0]="\t\t".'////////////// End Account Type - Changes Required/////////////'."\r\n";
$replace_02[1]="\t\t".'}'."\r\n";
$replace_02[2]="\t\t".'    }'."\r\n";
$replace_02[3]="\t\t".'        }'."\r\n";
$replace_02[...    and so forth....

 

Notice that for each search line that we defined in the $search array there should be a corresponding $replace_xx array

 

Ok now lets define our function...

function find_and_replace($far, $search, $file, $replace, $line_shift)
{
// $far case values: 1=Find, 2=Add, 3=Replace
    $subject = file($file);
    $first_appearance = array_search($search,$subject);
    $keys = array_keys($subject,$search);
    switch ($far) {
        case 1: //Search
            echo "Match found ".count($keys)." times." ;
            return;
        case 2: //Add
            // $lineshift = amount of lines to move the insertion point
            $temp_array = array_slice($subject, $first_appearance+$line_shift);
            foreach ($replace as $v) array_unshift($temp_array,$v);
            array_splice($subject, $first_appearance+$line_shift, count($subject), $temp_array);
            file_put_contents($file, $subject);
            echo "Code Successfully Added.<br>";
            break;
        case 3:  //Replace
            // $lineshift = amount of lines to replace
            $temp_array = array_slice($subject, $first_appearance);
            $temp_array = array_slice($temp_array, $line_shift);
            foreach ($replace as $v) array_unshift($temp_array,$v);
            array_splice($subject, $first_appearance, count($subject), $temp_array);
            file_put_contents($file, $subject);
            echo "Code Successfully Replaced.<br>";
            break;
    }
}

 

I think it is pretty self explanatory...

 

Ok this is the line that calls the function...

 

find_and_replace(2,$search[1],$file,$replace_01, -3);

 

The parameters are as follow:

  • $far --> Parameter to determine the action (1=search, 2=add or 3=replace).
  • $search --> The string to search for.
  • $file --> The file to work with.
  • $replace --> The replacement or add text.
  • $line_shift --> If it´s addin text this is the amount of lines to move the insertion point (+=down, -=up), but if it´s replacing then this is the amount of lines to replace.

 

This way although it maight not be pretty, I can work arround what´s posted on the first post. Any suggestions on how to make it better...  Thanks to all who helped me...

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.