How to make a tree from a flat array - php - php

I am trying to represent the whole array returned from Amazon S3 bucket in a tree structure one can browse.
The array example is following
$files[0] = 'container/798/';
$files[1] = 'container/798/logo.png';
$files[2] = 'container/798/test folder/';
$files[3] = 'container/798/test folder/another folder/';
$files[4] = 'container/798/test folder/another folder/again test/';
$files[5] = 'container/798/test folder/another folder/test me/';
$files[6] = 'container/798/test two/';
$files[7] = 'container/798/test two/logo2.png';
and this is what i am trying to achieve
http://i.stack.imgur.com/HBjvE.png
so far i have only achieved differing the files and folder but not on different level with parent-child relation. The above mentioned array resides in $keys['files']. The code is following
$keys = json_decode($result,true);
$folders = array();
$files = array();
$i =0;
foreach ($keys['files'] as $key){
if(endsWith($key, "/")){
$exploded = explode('container/'.$_SESSION['id_user'].'/',$key);
if(!empty($exploded[1]))
$folders[$i]['name'] = substr($exploded[1],0,-1);
}
else{
$exploded = explode('container/'.$_SESSION['id_user'].'/',$key);
$files[$i]['name'] = $exploded[1];
$files[$i]['size'] = "";
$files[$i]['date'] = "";
$files[$i]['preview_icon'] = "";
$files[$i]['dimensions'] = "";
$files[$i]['url'] = "";
}
$i++;
}
This is code just to show i am trying but its not complete or accurate. I don't know how to approach a logic that can give me the hierarchy i am showing the picture. Any help would be greatly appreciated.

I don't know if this is the 'correct' way to do this, but if you want to make a recursive structure, then the easy way is to use a recursive function:
$root = array('name'=>'/', 'children' => array(), 'href'=>'');
function store_file($filename, &$parent){
if(empty($filename)) return;
$matches = array();
if(preg_match('|^([^/]+)/(.*)$|', $filename, $matches)){
$nextdir = $matches[1];
if(!isset($parent['children'][$nextdir])){
$parent['children'][$nextdir] = array('name' => $nextdir,
'children' => array(),
'href' => $parent['href'] . '/' . $nextdir);
}
store_file($matches[2], $parent['children'][$nextdir]);
} else {
$parent['children'][$filename] = array('name' => $filename,
'size' => '...',
'href' => $parent['href'] . '/' . $filename);
}
}
foreach($files as $file){
store_file($file, $root);
}
Now, every element of root['children'] is an associative array that hash either information about a file or its own children array.

Related

Associative Array concat value to another associative array

What I have here is a delete multiple file function in codeigniter. I need to merge or concat the value only of associative array. The value of both array was the file name and file extension of an image/file. I used md5 to change the name of the file.
This is my code
public function delete_files(){
$filesCount = count($_FILES['file_certificate']['name']);
$file_certificate = [];
$y = 0;
for($i = 0; $i < $filesCount; $i++){
$_FILES['file_certificates']['name'] = $_FILES['file_certificate']['name'][$i];
$_FILES['file_certificates']['type'] = $_FILES['file_certificate']['type'][$i];
$_FILES['file_certificates']['tmp_name'] = $_FILES['file_certificate']['tmp_name'][$i];
$_FILES['file_certificates']['error'] = $_FILES['file_certificate']['error'][$i];
$_FILES['file_certificates']['size'] = $_FILES['file_certificate']['size'][$i];
$oldname = $_FILES["file_certificates"]['name'];
$file_ext[] = pathinfo($oldname,PATHINFO_EXTENSION);
$file_ray[] = trim(strtolower(md5(time().$oldname)));
$result = array_combine($file_ray, $file_ext);
}
$path = FCPATH . 'uploads/certificate/';
array_map('unlink', $result);
}
Here's my array right now
enter image description here
I need it like this
Array
(
[0] => 46eced0ea722a94160d53b4abbb10381.jpg
[1] => 4f9ca54fa1daa022dc31b991a673cab7.pdf
)
And also I never try this if its works deleting a multiple file via this code
$path = FCPATH . 'uploads/certificate/'; //path file location
array_map('unlink', $result);
Thank you.
I got this done using foreach.
$path = FCPATH . 'uploads/certificate/';
$data = array();
foreach( $file_ray as $index => $code ) {
$value = $path.$code.'.'.$file_ext[$index];
$data[] = $value;
}

Transform a monodimensional PHP array into a multidimensional one

How would you transform a monodimensional array into a multidimensional array in PHP? Suppose you have something like this
$array['breakfast'] = 'milk';
$array['meal.firstdish'] = 'pasta';
$array['meal.seconddish.maincourse'] = 'veal';
$array['meal.seconddish.dressing'] = 'fries';
$array['meal.dessert'] = 'pie';
And you want a function to transform it into
$array['breakfast'] = 'milk';
$array['meal']['firstdish'] = 'pasta';
$array['meal']['seconddish']['maincourse'] = 'veal';
$array['meal']['seconddish']['dressing'] = 'fries';
$array['meal']['dessert'] = 'pie';
The same function should of course transform
$tire['ean'] = '3286347717116';
$tire['brand.maker'] = 'BRIDGESTONE';
$tire['brand.model.name'] = 'POTENZA';
$tire['brand.model.variant'] = 'RE 040 RFT * SZ';
into
$tire['ean'] = '3286347717116';
$tire['brand']['maker'] = 'BRIDGESTONE';
$tire['brand']['model']['name'] = 'POTENZA';
$tire['brand']['model']['variant'] = 'RE 040 RFT * SZ';
I was thinking of using explode, then eval on the results, but eval always feels like cheating to me and I guess it would keep my code from running in HipHop.
The reason I want to do this is that I have to export lots of different tables from a database into XML files, and I already have a robust function that turns a multidimensional array into XML.
Like this:
function build(array &$trg, array $k,$key,$value) {
$p = &$trg;
while ( !empty($k) ) {
$nk = array_shift($k);
if ( !isset($p[$nk]) ) {
$p[$nk] = [];
}
$p = &$p[$nk];
}
$p[$key] = $value;
return $p;
}
$array['breakfast'] = 'milk';
$array['meal.firstdish'] = 'pasta';
$array['meal.seconddish.maincourse'] = 'veal';
$array['meal.seconddish.dressing'] = 'fries';
$array['meal.dessert'] = 'pie';
$out = [];
foreach ($array as $key => $value ) {
$path = explode('.',$key);
$last = array_pop($path);
build($out,$path,$last,$value);
}
print_r($out);
You were on the right track with explode, but there's no need to use eval. Once you've got the pieces of the keys available, you can loop over them and incrementally assign a pointer into a new array:
<?php
$array['breakfast'] = 'milk';
$array['meal.firstdish'] = 'pasta';
$array['meal.seconddish.maincourse'] = 'veal';
$array['meal.seconddish.dressing'] = 'fries';
$array['meal.dessert'] = 'pie';
$result = [];
$target = null;
foreach ($array as $key => $value) {
// Start by targeting the base of our resulting array
$target =& $result;
// Break the keys apart into pieces
$keyParts = explode('.', $key);
// Assign new target based on indexing into the result array one "piece" at a time
while ($part = array_shift($keyParts)) {
$target =& $target[$part];
}
// Finally, assign the value to our target
$target = $value;
}
See https://eval.in/625627

How write arrays name while parsing an ini file in PHP?

I am using parse_ini_file to parse an ini file using PHP.
Now I first upload an INI file to my server then open it and allow user to mak custom changes to the file.
Now once users has edited the file i get the data from post and save the file back to server. But Now i dont get my sections. INIdetails,Dialplan in the updated file so when i also want to write that to file how to do that?
This is the code :
$this->data['parameters'] = parse_ini_file($path.$filename,true);
/*Getting Our POST DATA from View*/
$data = array(
'SipUserName' => $this->input->post('SipUserName') ,
'SipAuthName' => $this->input->post('SipAuthName'),
'DisplayName' => $this->input->post('DisplayName'),
'Password' => $this->input->post('Password'),
'Domain' => $this->input->post('Domain'),
'Proxy' => $this->input->post('Proxy'),
'Port' => $this->input->post('Port'),
'ServerMode' => $this->input->post('ServerMode'),
'Param_1' => $this->input->post('Param_1'),
'Param_2' => $this->input->post('Param_2')
);
/*Creating New file with the name of customer loggedin*/
$name = $this->session->userdata('username');
$ext = $this->session->userdata('extension');
$custom_file = fopen('uploads/'.$name.'_'.$ext.'.ini', 'w');
fwrite($custom_file, "[INIDetails]\n");
foreach ($data as $key => $value)
{
fwrite($custom_file, " $key = $value\n");
}
fclose($custom_file);
/*Setting path to New CUSTOM file with customer name as prefix*/
$file = $path.$custom_file;
function write_php_ini($array, $file)
{
$res = array();
foreach($array as $key => $val)
{
if(is_array($val))
{
$res[] = "[$key]";
foreach($val as $skey => $sval) $res[] = "$skey = ".(is_numeric($sval) ? $sval : '"'.$sval.'"');
}
else $res[] = "$key = ".(is_numeric($val) ? $val : '"'.$val.'"');
}
safefilerewrite($file, implode("\r\n", $res));
}
function safefilerewrite($fileName, $dataToSave)
{ if ($fp = fopen($fileName, 'w'))
{
$startTime = microtime(TRUE);
do
{ $canWrite = flock($fp, LOCK_EX);
// If lock not obtained sleep for 0 - 100 milliseconds, to avoid collision and CPU load
if(!$canWrite) usleep(round(rand(0, 100)*1000));
} while ((!$canWrite)and((microtime(TRUE)-$startTime) < 5));
//file was locked so now we can store information
if ($canWrite)
{ fwrite($fp, $dataToSave);
flock($fp, LOCK_UN);
}
fclose($fp);
}
}
/*Creates ini file, dumps array to string and creates .INI file*/
write_php_ini($data,$file);
The culprit from your previous code is that your array is not formatted correctly, it should be array of arrays to achieve what you want.
Try below code:
// First read the ini file that the user was editing
// Your idea to read the existing ini file is good, since it will generate you the structured array
$previous_data = parse_ini_file($path . $filename, true);
// Overwrite/edit the previous_data using user's post data
$previous_data['INIDetails']['SipUserName'] = $this->input->post('SipUserName');
$previous_data['INIDetails']['Password'] = $this->input->post('Password');
$previous_data['INIDetails']['Domain'] = $this->input->post('Domain');
$previous_data['INIDetails']['Proxy'] = $this->input->post('Proxy');
$previous_data['INIDetails']['Port'] = $this->input->post('Port');
$previous_data['INIDetails']['SipAuthName'] = $this->input->post('SipAuthName');
$previous_data['INIDetails']['DisplayName'] = $this->input->post('DisplayName');
$previous_data['INIDetails']['ServerMode'] = $this->input->post('ServerMode');
$previous_data['INIDetails']['UCServer'] = $this->input->post('UCServer');
$previous_data['INIDetails']['UCUserName'] = $this->input->post('UCUserName');
$previous_data['INIDetails']['UCPassword'] = $this->input->post('UCPassword');
$previous_data['DialPlan']['DP_Exception'] = $this->input->post('DP_Exception');
$previous_data['DialPlan']['DP_Rule1'] = $this->input->post('DP_Rule1');
$previous_data['DialPlan']['DP_Rule2'] = $this->input->post('DP_Rule2');
$previous_data['DialPlan']['OperationMode'] = $this->input->post('OperationMode');
$previous_data['DialPlan']['MutePkey'] = $this->input->post('MutePkey');
$previous_data['DialPlan']['Codec'] = $this->input->post('Codec');
$previous_data['DialPlan']['PTime'] = $this->input->post('PTime');
$previous_data['DialPlan']['AudioMode'] = $this->input->post('AudioMode');
$previous_data['DialPlan']['SoftwareAEC'] = $this->input->post('SoftwareAEC');
$previous_data['DialPlan']['EchoTailLength'] = $this->input->post('EchoTailLength');
$previous_data['DialPlan']['PlaybackBuffer'] = $this->input->post('PlaybackBuffer');
$previous_data['DialPlan']['CaptureBuffer'] = $this->input->post('CaptureBuffer');
$previous_data['DialPlan']['JBPrefetchDelay'] = $this->input->post('JBPrefetchDelay');
$previous_data['DialPlan']['JBMaxDelay'] = $this->input->post('JBMaxDelay');
$previous_data['DialPlan']['SipToS'] = $this->input->post('SipToS');
$previous_data['DialPlan']['RTPToS'] = $this->input->post('RTPToS');
$previous_data['DialPlan']['LogLevel'] = $this->input->post('LogLevel');
// Set Name of New file with the name of customer logged in
$name = $this->session->userdata('username');
$ext = $this->session->userdata('extension');
$custom_file = "$name_$ext.ini";
$new_filename = $path . $custom_file;
// Write the INI file
write_php_ini($data, $new_filename);
function write_php_ini($array, $new_filename)
{
$res = array();
foreach ($array as $key => $val) {
if (is_array($val)) {
$res[] = "[$key]";
foreach ($val as $skey => $sval) {
$res[] = "$skey = " . (is_numeric($sval) ? $sval : '"' . $sval . '"');
}
} else {
$res[] = "$key = " . (is_numeric($val) ? $val : '"' . $val . '"');
}
}
safefilerewrite($new_filename, implode("\r\n", $res));
}
function safefilerewrite($new_filename, $dataToSave)
{
if ($fp = fopen($new_filename, 'w')) {
$startTime = microtime(true);
do {
$canWrite = flock($fp, LOCK_EX);
// If lock not obtained sleep for 0 - 100 milliseconds, to avoid collision and CPU load
if (!$canWrite) {
usleep(round(rand(0, 100) * 1000));
}
} while ((!$canWrite) and ((microtime(true) - $startTime) < 5));
//file was locked so now we can store information
if ($canWrite) {
fwrite($fp, $dataToSave);
flock($fp, LOCK_UN);
}
fclose($fp);
}
}
From your previous code, there are bunch of inappropriate codes which I remove. Also, too many inconsistencies like Method naming, variable naming etc.
If your function was named Camel cased then through out your code it must be named as camel-cased. If your variables are with underscore, then through out your code, they must have underscore for two or more worded variable.
I didn't edit the naming convention of your code so you won't be confused but i suggest to have a consistent naming convention through out your project.
UPDATED:
based on your answer, it seems like you changed your whole code. I would like to provide another way using nested foreach and passing by reference that save couple of lines:
$this->data['params'] = $this->parameter_m->get();
$this->data['parameters'] = parse_ini_file($path . $filename, true);
foreach ($this->data['parameters'] as $key_header => &$value_header) {
foreach ($value_header as $key_item => &$value_item) {
$value_item = $this->input->post($key_item);
}
}
$this->load->helper('file');
$this->load->library('ini');
$file = $path . $filename;
$ini = new INI($file);
$ini->read($file);
$ini->write($file, $this->data['parameters']);
Finally i got an answer:
I will loop through what i get from POST and will get each array's key. And then i will give the resultant to my Write Method
$this->data['params'] = $this->parameter_m->get();
/*Getting the parameters to display on view*/
$this->data['parameters'] = parse_ini_file($path.$filename,true);
while (current($this->data['parameters']) )
{
$param_set = current($this->data['parameters']);
$param_type = key($this->data['parameters']);
foreach ($param_set as $key =>$value)
{
$this->data['parameters'][$param_type][$key] = $this->input->post($key);
}
next($this->data['parameters']);
}
$this->load->helper('file');
$this->load->library('ini');
$file = $path.$filename;
$ini = new INI($file);
$ini->read($file);
$ini->write($file, $this->data['parameters']);

How to get Contents of text files as value in foreach loop in glob function in php?

I am developing a search engine with vector space Model. I successfully computed tf-idf with associative array data already define in code. Now I want that data should be come from directory where I have a folders and in each folder there is a number of text files with dummy data. I have tried alot but stuck at 1 point using glob function because I want all .txt files as key and its contents as value in foreach loop of glob function.... Below is my code.
Tf-idf With Associative Array Data
$collection = array(
1 => 'this string is a short string but a good string',
2 => 'this one isn\'t quite like the rest but is here',
3 => 'this is a different short string that\' not as short'
);
$dictionary = array();
$docCount = array();
foreach($collection as $docID => $doc) {
$terms = explode(' ', $doc);
$docCount[$docID] = count($terms);
foreach($terms as $term) {
if(!isset($dictionary[$term])) {
$dictionary[$term] = array('df' => 0, 'postings' => array());
}
if(!isset($dictionary[$term]['postings'][$docID])) {
$dictionary[$term]['df']++;
$dictionary[$term]['postings'][$docID] = array('tf' => 0);
}
$dictionary[$term]['postings'][$docID]['tf']++;
}
}
$temp = ('docCount' => $docCount, 'dictionary' => $dictionary);
As you see in 1st foreach loop is that $DocID is key and $doc is its contents(value) of collection array. But I don't know how to implement exact same thing when files read from directory. See code below..
Tf-idf With .txt Files and its contents read from directory
foreach (glob("C:\\wamp\\www\\Web-info\\documents\\awd_1990_00\\*.txt") as $file) {
$file_handle = fopen($file, "r");
//echo $file;
$dictionary = array();
$docCount = array();
foreach($file as $docID=> $value) {
echo $value;
$terms = explode(' ', $doc);
$docCount[$docID] = count($terms);
foreach($terms as $term) {
if(!isset($dictionary[$term])) {
$dictionary[$term] = array('df' => 0, 'postings' => array());
}
if(!isset($dictionary[$term]['postings'][$docID])) {
$dictionary[$term]['df']++;
$dictionary[$term]['postings'][$docID] = array('tf' => 0);
}
$dictionary[$term]['postings'][$docID]['tf']++;
}
}
}
$temp = array('docCount' => $docCount, 'dictionary' => $dictionary);
This gives me error on 1st foreach loop that invalid arugument supplied for foreach loop. As I mentioned earlier I want .txt files as a key and its contents as a value in 1st foreach loop. But I got this error Can anybody please Tell me how to do this.. Thanks in advance..
If you want to treat the entire file as one value, you can use file_get_contents() to read the file into a string:
$dictionary = array();
$docCount = array();
foreach (glob("C:\\wamp\\www\\Web-info\\documents\\awd_1990_00\\*.txt") as $docID) {
$value = file_get_contents($docID);
...
}

CSV file to flat array with materialized path

I have CSV file which contains a list of files and directories:
Depth;Directory;
0;bin
1;basename
1;bash
1;cat
1;cgclassify
1;cgcreate
0;etc
1;aliases
1;audit
2;auditd.conf
2;audit.rules
0;home
....
Each line depends on the above one (for the depth param)
I would like to create an array like this one in order to store it into my MongoDB collection with Materialized Paths
$directories = array(
array('_id' => null,
'name' => "auditd.conf",
'path' => "etc,audit,auditd.conf"),
array(....)
);
I don't know how to process...
Any ideas?
Edit 1:
I'm not really working with directories - it's an example, so I cannot use FileSystems functions or FileIterators.
Edit 2:
From this CSV file, I'm able to create a JSON nested array:
function nestedarray($row){
list($id, $depth, $cmd) = $row;
$arr = &$tree_map;
while($depth--) {
end($arr );
$arr = &$arr [key($arr )];
}
$arr [$cmd] = null;
}
But i'm not sure it's the best way to proceed...
This should do the trick, I think (it worked in my test, at least, with your data). Note that this code doesn't do much error checking and expects the input data to be in proper order (i.e. starting with level 0 and no holes).
<?php
$input = explode("\n",file_get_contents($argv[1]));
array_shift($input);
$data = array();
foreach($input as $dir)
{
if(count($parts = str_getcsv($dir, ';')) < 2)
{
continue;
}
if($parts[0] == 0)
{
$last = array('_id' => null,
'name' => $parts[1],
'path' => $parts[1]);
$levels = array($last);
$data[] = $last;
}
else
{
$last = array('id' => null,
'name' => $parts[1],
'path' => $levels[$parts[0] - 1]['path'] . ',' . $parts[1]);
$levels[$parts[0]] = $last;
$data[] = $last;
}
}
print_r($data);
?>
The "best" way to go would be to not store your data in CSV format, as it's the Wrong Tool For The Job.
That said, here you go:
<?php
$lines = file('/path/to/your/csv_file.csv');
$directories = array();
$path = array();
$lastDepth = NULL;
foreach ($lines as $line) {
list($depth, $dir) = str_getcsv($line, ';');
// Skip headers and such
if (!ctype_digit($depth)) {
continue;
}
if ($depth == $lastDepth) {
// If this depth is the same as the last, pop the last directory
// we added off the stack
array_pop($path);
} else if ($depth == 0) {
// At depth 0, reset the path
$path = array();
}
// Push the current directory onto the path stack
$path[] = $dir;
$directories[] = array(
'_id' => NULL,
'name' => $dir,
'path' => implode(',', $path)
);
$lastDepth = $depth;
}
var_dump($directories);
Edit:
For what it's worth, once you have the desired nested structure in PHP, it would probably be a good idea to use json_encode(), serialize(), or some other format to store it to disk again, and get rid of the CSV file. Then you can just use json_decode() or unserialize() to get it back in PHP array format whenever you need it again.

Categories