How to parse file with PHP - php

I have this file, I cant figure out how to parse this file.
type = 10
version = 1.2
PART
{
part = foobie
partName = foobie
EVENTS
{
MakeReference
{
active = True
}
}
ACTIONS
{
}
}
PART
{
part = bazer
partName = bazer
}
I want this to be a array which should look like
$array = array(
'type' => 10,
'version' => 1.2,
'PART' => array(
'part' => 'foobie',
'partName' => 'foobie,
'EVENTS' => array(
'MakeReference' => array(
'active' => 'True'
)
),
'ACTIONS' => array(
)
),
'PART' => array(
'part' => 'bazer',
'partName' => 'bazer'
)
);
I tried with preg_match but that was not a success.
Any ideas?

Why not use a format that PHP can decode natively, like JSON?
http://php.net/json_decode
$json = file_get_contents("filename.txt");
$array = json_decode($json);
print_r($array);

Here is my approach.
First of all change Im changing the { to the line before.
Thats pretty easy
$lines = explode("\r\n", $this->file);
foreach ($lines as $num => $line) {
if (preg_match('/\{/', $line) === 1) {
$lines[$num - 1] .= ' {';
unset($lines[$num]);
}
}
Now the input looks like this
PART {
part = foobie
Now we can make the whole thing to XML instead, I know that I said a PHP array in the question, but a XML object is still fine enough.
foreach ($lines as $line) {
if (preg_match('/(.*?)\{$/', $line, $matches)) {
$xml->addElement(trim($matches[1]));
continue;
}
if (preg_match('/\}/', $line)) {
$xml->endElement();
continue;
}
if (strpos($line, ' = ') !== false) {
list($key, $value) = explode(' = ', $line);
$xml->addElementAndContent(trim($key), trim($value));
}
}
The addElement, actually just adds a to a string
endElement adds a and addElementAndContent doing both and also add content between them.
And just for making the whole content being a XML object, im using
$xml = simplexml_load_string($xml->getXMLasText());
And now $xml is a XML object, which is so much easier to work with :)

Related

PHP: How to find and replace values for a key with random text from a list in a varying-length array

I have a varying array for a playlist, containing media/source URLs for each item. Like this:
$playlist = array(
array(
"title" => "something",
"sources" => array(
array(
"file" => "https://url.somedomain.com/path/file1.mp3"
)
),
"description" => "somedesc",
"image" => "http://imagepath/",
"file" => "https://url.somedomain.com/path/file1.mp3"
),
array(
"title" => "elsewaa",
"sources" => array(
array(
"file" => "https://url.somedomain.com/someother/file2.mp3"
)
),
"description" => "anotherdesc",
"image" => "http://someotherimagepath/",
"file" => "https://url.somedomain.com/someother/file2.mp3"
)
);
How do I find and replace the values in the file keys to 'randomise' the choice of subdomain?
For example, if the file key contains url.foo.com, how do I replace the url.foo.com portion of the array value with either differentsubdomain.foo.com or anotherplace.foo.com or someotherplace.foo.com?
I was kindly offered a solution for a single string in this question/answer that used str_replace (thanks Qirel!), but I need a solution that tackles the above array configuration specifically.
All the nesting in the array does my head in!
Is it possible to adapt Qirel's suggestion somehow?
$random_values = ['differentsubdomain.foo.com', 'anotherplace.foo.com', 'someotherplace.foo.com'];
$random = $random_values[array_rand($random_values)];
// str_replace('url.foo.com', $random, $file);
If you are just asking how to access members in nested arrays, I think you want this:
$random_values = ['differentsubdomain.foo.com', 'anotherplace.foo.com', 'someotherplace.foo.com'];
// Iterate through the array, altering the items by reference.
foreach ($playlist as &$item) {
$random_key = array_rand($random_values);
$new_domain = $random_values[$random_key];
$item['file'] = str_replace('url.foo.com', $new_domain);
$item['sources'][0]['file'] = str_replace('url.foo.com', $new_domain);
}
Here's an example using recursion to replace the subdomains in any keys named file with a random one.
function replaceUrlHost(&$array, $hostDomain, $subdomains)
{
foreach ($array as $key => $value) {
if (is_array($value)) {
$array[$key] = replaceUrlHost($value, $hostDomain, $subdomains);
continue;
}
if ($key !== 'file') {
continue;
}
$hostname = parse_url($value, PHP_URL_HOST);
if (strpos($hostname, $hostDomain) === false) {
continue;
}
$array[$key] = str_replace(
$hostname,
$subdomains[array_rand($subdomains)] . '.' . $hostDomain,
$value
);
}
return $array;
}
// usage
$subdomains = ['bar', 'baz', 'bing', 'bop'];
$out = replaceUrlHost($playlist, 'somedomain.com', $subdomains);

PHP: Convert Multidimensional Array to String

I am trying to convert a multidimensional array into a string.
Till now I have been able to convert a pipe delimited string into an array.
Such as:
group|key|value
group|key_second|value
Will render into the following array:
$x = array(
'group' => array(
'key' => 'value',
'key_second' => 'value'
),
);
However, now I want it to be the other way around, where a multidimensional array is provided and I want to convert it to a pipe delimited string just like in the first code example.
Any ideas how to do this ?
PS: Please do note that the array can dynamically have any depth.
For example:
$x['group']['sub_group']['category']['key'] = 'value'
Translates to
group|sub_group|category|key|value
I have created my own function:
This should have no problem handling even big arrays
function array_to_pipe($array, $delimeter = '|', $parents = array(), $recursive = false)
{
$result = '';
foreach ($array as $key => $value) {
$group = $parents;
array_push($group, $key);
// check if value is an array
if (is_array($value)) {
if ($merge = array_to_pipe($value, $delimeter, $group, true)) {
$result = $result . $merge;
}
continue;
}
// check if parent is defined
if (!empty($parents)) {
$result = $result . PHP_EOL . implode($delimeter, $group) . $delimeter . $value;
continue;
}
$result = $result . PHP_EOL . $key . $delimeter . $value;
}
// somehow the function outputs a new line at the beginning, we fix that
// by removing the first new line character
if (!$recursive) {
$result = substr($result, 1);
}
return $result;
}
Demo provided here http://ideone.com/j6nThF
You can also do this using a loop like this:
$x = array(
'group' => array(
'key' => 'value',
'key_second' => 'value'
)
);
$yourstring ="";
foreach ($x as $key => $value)
{
foreach ($x[$key] as $key2 => $value2)
{
$yourstring .= $key.'|'.$key2.'|'.$x[$key][$key2]."<BR />";
}
}
echo $yourstring;
Here is a working DEMO
This code should do the thing.
You needed a recursive function to do this. But be careful not to pass object or a huge array into it, as this method is very memory consuming.
function reconvert($array,$del,$path=array()){
$string="";
foreach($array as $key=>$val){
if(is_string($val) || is_numeric($val)){
$string.=implode($del,$path).$del.$key.$del.$val."\n";
} else if(is_bool($val)){
$string.=implode($del,$path).$del.$key.$del.($val?"True":"False")."\n";
} else if(is_null($val)){
$string.=implode($del,$path).$del.$key.$del."NULL\n";
}else if(is_array($val)=='array') {
$path[]=$key;
$string.=reconvert($val,$del,$path);
array_pop($path);
} else {
throw new Exception($key." has type ".gettype($val).' which is not a printable value.');
}
}
return $string;
}
DEMO: http://ideone.com/89yLLo
You can do it by
Look at serialize and unserialize.
Look at json_encode and json_decode
Look at implode
And Possible duplicate of Multidimensional Array to String
You can do this if you specifically want a string :
$x = array(
'group' => array(
'key' => 'value',
'key_second' => 'value'
),
'group2' => array(
'key2' => 'value',
'key_second2' => 'value'
),
);
$str='';
foreach ($x as $key=>$value)
{
if($str=='')
$str.=$key;
else
$str.="|$key";
foreach ($value as $key1=>$value1)
$str.="|$key1|$value1";
}
echo $str; //it will print group|key|value|key_second|value|group2|key2|value|key_second2|value

how to dynamically add values to an array

Here is the working script with hard coded values:
$subject->currentCert['tbsCertificate']['extensions'][] = array(
'extnId' => 'id-ce-subjectAltName',
'critical' => false,
'extnValue' => array(
array('dNSName' => 'www.domain1.com'),
array('dNSName' => 'www.domain2.com')
)
);
I would like to update the above script (extnValue section only) to automatically take values from a another array called $OPTIONS["altnames"]
First I convert the following string to an array
$sans = 'www.domain1.com, www.domain2.com';
I converted the string to an array $OPTIONS["altnames"] with the following code:
$OPTIONS["altnames"] = array();
if ( !empty($sans) ) {
if (strpos($sans,",") !== false) {
$sans = str_replace(" ", "", $sans); //remove spaces
$sans = explode(",", $sans); //strip each value after comma to array
foreach ($sans as $value) {
array_push($OPTIONS["altnames"], $value);
}
}
}
Not sure what to do next
You need to add another level of array in the extnValue array when you copy it from $OPTIONS['altnames']:
$extnValues = array();
foreach ($OPTIONS['altnames'] AS $name) {
$extnValues[] = array('dNSName' => $name);
}
$subject->currentCert['tbsCertificate']['extensions'][] = array(
'extnId' => 'id-ce-subjectAltName',
'critical' => false,
'extnValue' => $extnValues
);

Replace variable texts with regular expressions

I'm reformulating one of my old programs and using TextCrawler to automate text replacements in several code files, but I'm struggling to make the following change:
I need to find all 'text' functions (example):
$object->text('TRANSLATE_KEY_A')
$object->text('TRANSLATE_KEY_B')
...
and replace them with (example):
__('RETURNED_TEXT_FROM_TRANSLATE_KEY_A', TEXT_DOMAIN)
__('RETURNED_TEXT_FROM_TRANSLATE_KEY_B', TEXT_DOMAIN)
...
Where RETURNED_TEXT_FROM_TRANSLATE_KEY_X are set with the 'text' array's key in another code file
array_push($text, array('key' => 'TRANSLATE_KEY_A',
'extras' => '',
'text' => 'Translated Text A'));
array_push($text, array('key' => 'TRANSLATE_KEY_B',
'extras' => '',
'text' => 'Translated Text B'));
The final result should be:
$object->text('TRANSLATE_KEY_A')
$object->text('TRANSLATE_KEY_B')
...
replaced with
__('Translated Text A', TEXT_DOMAIN)
__('Translated Text B', TEXT_DOMAIN)
...
There are over 1500 of these :(
Is it possible to achieve this with regular expression in TextCrawler, and how? Or any other idea? Thanks
If you want to use a php array to provide the replacement data it is probably best to just use php itself for the task.
Example script.php:
// your $text array
$text = array();
array_push($text, array(
'key' => 'TRANSLATE_KEY_A',
'extras' => '',
'text' => 'Translated Text A')
);
array_push($text, array(
'key' => 'TRANSLATE_KEY_B',
'extras' => '',
'text' => 'Translated Text B')
);
...
// create a separate array from your $text array for easy lookup
$data_arr = array();
foreach ($text as $val) {
$data_arr[$val['key']] = $val['text'];
}
// your code file, passed as first argument
$your_code_file = $argv[1];
// open file for reading
$fh = fopen($your_code_file, "r");
if ($fh) {
while (($line = fgets($fh)) !== false) {
// check if $line has a 'text' function and if the key is in $data_arr
// if so, replace $line with the __(...) pattern
if (preg_match('/^\$object->text\(\'([^\']+)\'\)$/', $line, $matches)
&& isset($data_arr[$matches[1]])) {
printf("__('%s', TEXT_DOMAIN)\n", $data_arr[$1]);
} else {
print($line);
}
}
fclose($fh);
} else {
print("error while opening file\n");
}
Call:
php script.php your_code_file
Just add functionality to iterate over all of your code files and write to the corresponding output files.

Print_r line bug ? \n?

I have this OUTPUT array from Decode function down:
Array ( [
] =>
[HostName] => Survival4fun
[GameType] => SMP
[Version] => 1.5.2
[Plugins] => Array
(
[0] => WorldEdit
)
[Map] => world
[Players] => 0
[MaxPlayers] => 10
[HostPort] => 25608
[HostIp] => 31.133.13.99
[RawPlugins] => WorldEdit5.5.6;
[Software] => CraftBukkitonBukkit1.5.2-R0.1
[Status] => online
[Ping] => 15ms
[
] =>
[PlayersOnline] => Array
(
[P0] => NoPlayers
)
[
] => )
And so, you can see this:
[
] =>
How can I remove it ? I tried using str_replace("\n", "", $arr); But this doesn't work.
Here is the original array - http://status.mc-host.cz/s8.mc-host.cz:25608-feed
And here is my function code:
Function Decode_query($link) {
$data = file($link, FILE_IGNORE_NEW_LINES);
$arr = array();
$string = array("[", "]", " ", "(", ")", "Array", "\n", "\r");
$replace = array("", "", "", "", "", "", "", "");
ForEach ($data as $line) {
$s = str_replace($string, $replace, $line);
If (Empty($s)) {} Else {
$stat = explode("=>", $s);
$P = str_replace("P", "", $stat[0]);
If (is_numeric($stat[0])) {
$arr["Plugins"][$stat[0]] = $stat[1];
}
ElseIf (is_numeric($P)) {
$arr['PlayersOnline'][$stat[0]] = $stat[1];
} Else {
$arr[$stat[0]] = $stat[1];
}
}
}
Return $arr;
}
$arr = Decode_query("http://status.mc-host.cz/s8.mc-host.cz:25608-feed");
Print_r($arr);
Thanks for help and sorry for long question..
You could use a regex to scan for keys that are composed of only whitespace:
$keys = array_keys($your_array);
$blank_keys = preg_grep('/^\s*$/', $keys);
foreach($blank_keys as $blank) {
unset($your_array[$blank]);
}
I would work with trim in stead of str_replace. It is less expensive, and it takes care of the trailing spaces and whatever whitespace there may be. In your case your function would probably look something like this:
Function Decode_query($link) {
// fetch the data
$data = file($link, FILE_IGNORE_NEW_LINES);
// prepare output array
$arr = array('Plugins' => array(), 'PlayersOnline' => array());
// prepare the list of characters we want to remove
$removeChars = ' \t\n\r[]';
ForEach ($data as $line) {
// split line into key, value
$stat = explode("=>", $line);
// no 2 elements, means no '=>', so ignore line
if (count($stat) < 2) continue;
// remove unwanted characters from key
$trimmed = trim($stat[0], $removeChars);
$pTrimmed = trim($trimmed, 'P');
// if key = plugins, ignore line
if ($trimmed == 'Plugins') continue;
// if key is numeric
If (is_numeric($trimmed)) {
// store in plugins subarray
$arr['Plugins'][$trimmed] = trim($stat[1]);
}
// if (key - P) is numeric
ElseIf (is_numeric($pTrimmed)) {
// store in players online subarray
$arr['PlayersOnline'][$pTrimmed] = trim($stat[1]);
} Else {
// all others store in level 1 array
$arr[$trimmed] = trim($stat[1]);
}
}
Return $arr;
}
I didn't test the code, but I think it should work fine.
PS: You can never put enough comments in your code, may seem a waste of time at first, but you, or anyone who has to work on your code, will be very grateful some day...

Categories