String replacing does not work. Am I overlooking something? - php

I am trying my best to build a generator for the fantastic WordPress Plugin Boilerplate by Tom Mc Farlin. All works out quite well. I load the file from github, extract it to a directory and replace all needed strings like 'plugin_name', 'Your name ' etc.
Unfortunately there is a protected class variable named $plugin_name and some other tiny bits. So I decided to 'repair' some flaws after replacing, like this:
// Repair some flaws
$repair_file = $newAbsDir.'/plugin-name/trunk/includes/class-'.$new_plugin_name.'.php';
$repair_file_content = file_get_contents($repair_file);
$repair_strings = array(
'$'.$new_plugin_name => '$plugin_name',
'$this->'.$new_plugin_name => '$this->plugin_name',
'get_'.$new_plugin_name => 'get_plugin_name'
);
foreach($repair_strings as $string => $replace){
$repair_file_content = str_replace($string, $replace, $repair_file_content);
}
file_put_contents($repair_file, $repair_file_content);
BUt what seemed to work quite well with my glob array of files, does simply not work with the above. I assume it has something to do with the dollar sign. Does anybody have an idea how to fix this?

From PHP manual:
If search and replace are arrays, then str_replace() takes a value from each array and uses them to search and replace on subject.
So, it's like Elias Van Ootegem said, do a simple str_replace() without foreach(). The array values are passed on the literal array and the keys on array_keys(). And as the array keys are the ones to be searched, you have to invert the array:
$repair_strings = array(
'$plugin_name' => '$'.$new_plugin_name,
'$this->plugin_name' => '$this->'.$new_plugin_name,
'get_plugin_name' => 'get_'.$new_plugin_name
);
$repair_file_content = str_replace( array_keys( $repair_strings ), $repair_strings, $repair_file_content );
Inverting the array is just to keep the logic search => replace, but to use your original array it's a matter of:
$repair_file_content = str_replace( $repair_strings, array_keys( $repair_strings ), $repair_file_content );

D'oh ...
$My_fantastic_plugin differs slightly from $my_fantastic_plugin. Sorry for the hassle and thank you for the good advice with $repair_file_content = str_replace( array_keys( $repair_strings ), $repair_strings, $repair_file_content );

Related

How to parse a mostly consistent filename into meaningful parts?

I have filenames like:
1234_56_78 A_FAIRLY_SHORT_TITLE_D.pdf
Luckily, the file naming is pretty consistent, but I can't absolutely guarantee that someone didn't use a space where they should have used an underscore.
With this in mind, I want to parse the string and extract the following details:
$project_no = '1234
$series_no = '56
$sheet_no = '78'
$revision = 'D'
$title = 'A Fairly Short Title'
Presently, I use the following to grab this info:
$filename = $_FILES['file']['name'][$i];
$filename = preg_replace('/\\.[^.\\s]{3,4}$/', '', $filename);
$parts = preg_split( "(_| )", $filename );
$project_no = $parts[0];
$series_no = $parts[1];
$sheet_no = $parts[2];
$revision = end($parts);
$title is simply everything that's left over after removing $parts[0] $parts[1], $parts[2], and end($parts), but how should I express that?
I thought I might be able to use
$title = implode(' ',\array_diff_key($parts, [0,1,2,end($parts)]));
But this doesn't remove the $revision bit at the end...
$title = FLOOR AS PROPOSED D
What am I missing, and am I unnecessarily over-complicating this?
The array_diff_key looks at key comparison of both arrays. end() just moves the internal pointer of the array and is actually useless since the value returned from it can't be used in computing difference between 2 arrays' keys.
Current comparison behaves as
array_diff_key([0,1,2,3,4,5,6,7], [0,1,2,'D'])
which looks key wise as:
array_diff_key([0,1,2,3,4,5,6,7], [0,1,2,3])
Hence, the end result of implode is concatenation of 4,5,6,7 keys' values.
To make the second parameter array values as keys, you can use array_flip to make keys as values and values as keys with the below expression:
$title = implode(' ',\array_diff_key($parts, array_flip([0,1,2,count($parts)-1])));
Demo: https://3v4l.org/J6b5r
I fear you are over-complicating this. I think a single preg_match() call is the most direct way to parse your string.
It looks like you grabbed the regex pattern from https://stackoverflow.com/a/2395905/2943403 to trim the extension from your filename; however, I recommend using a regex function when a single non-regex function serves the same purpose.
pathinfo($filename', PATHINFO_FILENAME)
Now that the extension has been removed, let's move on to the parsing.
Code: (Demo)
$filename = '1234_56_78 A_FAIRLY_SHORT_TITLE_D.pdf';
preg_match('~([^ _]+)[ _]([^ _]+)[ _]([^ _]+)[ _](.+)[ _](\S)~', pathinfo($filename, PATHINFO_FILENAME), $m);
var_export([
'project_no' => $m[1],
'series_no' => $m[2],
'sheet_no' => $m[3],
'title' => str_replace('_', ' ', $m[4]),
'revision' => $m[5],
]);
Output:
array (
'project_no' => '1234',
'series_no' => '56',
'sheet_no' => '78',
'title' => 'A FAIRLY SHORT TITLE',
'revision' => 'D',
)
If you are deadset on using preg_split(), then the pattern becomes super simple, but there is a little more mopping up to do.
Code: (Demo)
$filename = '1234_56_78 A_FAIRLY_SHORT_TITLE_D.pdf';
$m = preg_split('~ |_~', pathinfo($filename, PATHINFO_FILENAME));
$revision = array_pop($m);
var_export([
'project_no' => $m[0],
'series_no' => $m[1],
'sheet_no' => $m[2],
'title' => implode(' ', array_slice($m, 3)),
'revision' => $revision,
]);
// same output as earlier snippet

Multidimensional Array Not Echoing As Expected

I am setting this array manually:
$schools = array(
'Indiana University'=>array(
'initials'=>'IU',
'color'=>'red',
'directory'=>'indiana'
)
);
But it won't echo "IU" when I use:
echo $schools[0][0];
It does show correctly when I do:
print_r($schools);
I'm sure I'm messing up something dumb, but I have no idea what and I've been staring at it for hours. This array is actually part of a larger array with multiple universities, but when I trim it down to just this, it doesn't work.
PHP arrays support two types of keys - numerical and strings.
If you just push a value onto an array, it will use numerical keys by default. E.g.
$schools[] = 'Indiana University';
echo $schools[0]; // Indiana University
However, when you use string keys, you access the array values using the string key. E.g.
$schools = array(
'Indiana University' => array(
'initials' => 'IU',
'color' => 'red',
'directory' => 'indiana'
)
);
echo $schools['Indiana University']['initials']; // UI

Using str_replace() With Array Values Giving Unexpected Results

Using str_replace() to replace values in a couple paragraphs of text data, it seems to do so but in an odd order. The values to be replaced are in a hard-coded array while the replacements are in an array from a query provided by a custom function called DBConnect().
I used print_r() on both to verify that they are correct and they are: both have the same number of entries and are in the same order but the on-screen results are mismatched. I expected this to be straightforward and didn't think it needed any looping for this simple task as str_replace() itself usually handles that but did I miss something?
$replace = array('[MyLocation]','[CustLocation]','[MilesInc]','[ExtraDoc]');
$replacements = DBConnect($sqlPrices,"select",$siteDB);
$PageText = str_replace($replace,$replacements,$PageText);
and $replacements is:
Array
(
[0] => 25
[MyLocation] => 25
[1] => 45
[CustLocation] => 45
[2] => 10
[MilesInc] => 10
[3] => 10
[ExtraDoc] => 10
)
Once I saw what the $replacements array actually looked like, I was able to fix it by filtering out the numeric keys.
$replace = array('[MyLocation]','[CustLocation]','[MilesInc]','[ExtraDoc]');
$replacements = DBConnect($sqlPrices,"select",$siteDB);
foreach ($replacements as $key=>$value) :
if (!is_numeric($key)) $newArray[$key] = $value;
endforeach;
$PageText = str_replace($replace,$newArray,$PageText);
The former $replacements array, filtered to $newArray, looks like this:
Array
(
[MyLocation] => 25
[CustLocation] => 45
[MilesInc] => 10
[ExtraDoc] => 10
)
-- edited: Removed some non sense statements --
#DonP, what you are trying to do is possible.
In my opinion, the strtr() function could be more beneficial to you. All you need to make a few adjustments in your code like this ...
<?php
$replacements = DBConnect($sqlPrices,"select",$siteDB);
$PageText = strtr($PageText, [
'[MyLocation]' => $replacements['MyLocation'],
'[CustLocation]' => $replacements['CustLocation'],
'[MilesInc]' => $replacements['MilesInc'],
'[ExtraDoc]' => $replacements['ExtraDoc'],
]);
?>
This code is kinda verbose and requires writing repetitive strings. Once you understand the way it works, you can use some loops or array functions to refactor it. For example, you could use the following more compact version ...
<?php
// Reference fields.
$fields = ['MyLocation', 'CustLocation', 'MilesInc', 'ExtraDoc'];
// Creating the replacement pairs.
$replacementPairs = [];
foreach($fields as $field){
$replacementPairs["[{$field}]"] = $replacements[$field];
}
// Perform the replacements.
$PageText = strtr($PageText, $replacementPairs);
?>

PHP5: Adding stuff into a multidimensional array given a location of any length?

// given following array:
$data = array(
0=>array(
"data"=>"object1",
"col"=>array(
0=>array(
"data"=>"object2",
"col"=>array(
0=>array(
"data"=>"object3",
),
1=>array(
"data"=>"object4",
),
)
),
1=>array(
"data"=>"object5",
"col"=>array()
),
)
)
);
// A new object can be added or existing one replaced given a position of any length
// array(0), array(1,0), array(1,0,0), etc...
$data = add($data, array(0,0,1), "new_object");
function add($data, $position, $object) {
// this has to be produced based the location:
$data[0]["col"][0]["col"][1]["data"] = "new_object";
return $data;
}
Is there a sane way to do it in PHP besides creating $data."[0]["col"][0]["col"][1]["data"]" ?
There must be a better data structure than that tangled array. 6 dimensions is too many in most cases. It seems like there's some repeated structure in there. Perhaps you could capitalize on that? There's no "sane" way, as you put it, to access an insane array.

URL Regex for PHP framework

I'm trying to get the controller, method and queries from a URL array. Something like this:
'home/news/[day]/[month]/[slug]/'
I need some regex which will give me the following:
Controller: home
Method: News
Arguments: day, month, slug
For the arguments, it'd be nice if I could somehow get the name inside the brackets so I can put them into an associative array in PHP. e.g: ("day"=>$day).
I'm really stuck with this, and tried looking at several PHP frameworks for guidance but nothing really accomplishes exactly what I want above, especially using regex.
preg_match('{/home/news/(?<day>\d{1,2})/(?<month>\d{1,2})/(?<slug>[\w-]+)}',
'/home/news/10/02/foo',
$matches);
$matches is now
array (
0 => '/home/news/10/02/foo',
'day' => '10',
1 => '10',
'month' => '02',
2 => '02',
'slug' => 'foo',
3 => 'foo',
)
If you're always going to have /:controller/:method/:args you might as well use explode:
$args = explode('/', $url);
$controllerName = array_shift($args);
$method = array_shift($args);
$controller = new $controllerName;
$response = $controller->$method($args);

Categories