Remove specific parameters from a URL using PHP - php

So I'm attempting to remove specific parameters from the URL query string that are predefined in an array. Here's what I have so far:
<?php
// Construct the current page URL
$host = $_SERVER['HTTP_HOST'];
$script = $_SERVER['SCRIPT_NAME'];
$params = $_SERVER['QUERY_STRING'];
$currentUrl = 'http://' . $host . $script . '?' . $params;
// Store all URL parameters into an array (HOST, PATH, QUERY, etc)
$url_params = array();
$url_params = parse_url($currentUrl);
// Create an array to store just the query string, breaking them apart
$params_array = explode('&', $url_params['query']);
// Array holding URL parameters that we want to remove
$params_to_remove = array("param1", "param2", "param3", "param4", "param5");
$location = 0;
// Loop through and remove parameters found in PARAMS_TO_REMOVE array
for($x = 0; $x < count($params_to_remove); $x++) {
if(in_array($params_to_remove[$x], $params_array)) {
$location = array_search($params_to_remove[$x], $params_array);
unset($params_array[$location]);
}
}
// Print array after unwanted parameters were removed
print_r($params_array);
echo '<br /><br />';
// Construct a new array holding only the parameters that we want
$clean_params_array = array();
for($z = 0; $z < count($params_array); $z++) {
if($params_array[$z] != '') array_push($clean_params_array, $params_array[$z]);
}
// Print clean array
print_r($clean_params_array);
echo '<br />';
// Construct the new URL
// If there are paramters remaining in URL reconstruct them
if(count($clean_params_array) > 0) {
$final_url = 'http://www.example.com' . $url_params['path'] . '?';
for($y = 0; $y < count($clean_params_array); $y++) {
$final_url .= $clean_params_array[$y] . '&';
}
// Trim off the final ampersand
$final_url = substr($final_url, 0, -1);
}
// No parameters in final URL
else $final_url = 'http://www.example.com' . $url_params['path'];
// Print final URL
echo '<br />' . $final_url;
?>
Here's the output:
Using http://www.example.com/test.php?apple&banana&orange&param1&strawberry&param2&pineapple
Array ( [0] => apple [1] => banana [2] => orange [4] => strawberry [6] => pineapple )
Array ( [0] => apple [1] => banana [2] => orange [3] => strawberry )
http://www.example.com/test.php?apple&banana&orange&strawberry
As you can see I'm losing the last parameter. I also feel as if I'm being too verbose...where am I going wrong?

$new_url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."?".implode("&",array_diff(explode("&",$_SERVER['QUERY_STRING']),Array("param1","param2","param3","param4","param5")));
One-liner ;)
Although you'd probably be better off taking that Array(...) out of there and defining it as a variable beforehand, so it's easier to read.

<?php
/**
* generateURL()
*
* Sprava URL adresy
*
* #author stenley <stenley#webdev.sk>
* #version 1.4
*/
function generateURL() {
$GET = $_GET;
$QUERY_STRING = '';
$SCRIPT_NAME = substr(strrchr($_SERVER["SCRIPT_NAME"],"/"),1);
$num_args = func_num_args();
if($num_args>0 && $num_args%2==0) {
$args = func_get_args();
foreach($args as $index => $paramName) {
$paramName = trim($paramName);
if($index%2==0 && !empty($paramName)) {
$paramValue = trim($args[$index+1]);
if(array_key_exists($paramName, $GET) && empty($paramValue)) {
unset($GET[$paramName]);
} elseif(!empty($paramValue)) {
$GET[$paramName] = $paramValue;
}
}
}
}
foreach($GET as $param => $value) {
$QUERY_STRING .= $param."=".$value."&";
}
return $SCRIPT_NAME.((empty($QUERY_STRING)) ? '' : "?".substr($QUERY_STRING,0,-5));
}
?>
here is great function for managing URL address. usage is easy. here are some examples in Slovak language. but I think you will understand code samples. or I will translate it for you
sorry for my english

Part of the answer is in this line:
Array ( [0] => apple [1] => banana [2] => orange [4] => strawberry [6] => pineapple )
Note that $params_array[5] does not exist. Yet you try to read $params_array[5] when $z==5
(In your while loop you go through values $z = 0; => $z < 6; (count($params_array))
You can use Kolink's solution, or use a foreach loop to go through all the values:
foreach($params_array as $param) {
if($param != '') array_push($clean_params_array, $param);
}

Related

replace values of keys in json1 from Json2

I am very very new to php.. actually i am from java domain. But, i have to do some work in php for integration. My scenario is, i have one json array which will have 4 keys for ex:
one json --> {"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}.
I will be getting another JSON which ever edited from admin panel. for example if i updated any key, only that key will coming in the
second JSON --> for ex: {"blog_heading":"def"}
Now, i have to replace the value of second json to first json. example output for above scenario like I am very very new to php.. actually i am from java domain. But, i have to do some work in php for integration. My scenario is, i have one json array which will have 4 keys for ex:
output json --> {"id":7,"active":1,"blogId":"abc","blog_heading":"def"}.
So i am trying as below,
$id = json_decode($data_string);
$id2 = json_encode($post);
$id5 = json_decode($id2);
$id6 = array();
foreach ($id as $key => $value)
{
$log->debug($key . ': ' . $value);
if (array_key_exists($key, $id5->data)) {
$log->debug($key . 'element is in the array');
$log->debug($value . 'element is in the array');
//array_push($id5, "apple", "raspberry");
$id3 = array($key => $value);
$id3[$key] = $value;
$log->debug($id3);
}else{
$log->debug($key . 'element is not in the array');
}
}
$id7 = json_encode($id2);
$log->debug($id7);
id5 data is : $id5
DEBUG - 2017-06-05T02:26:20-04:00 - stdClass Object
(
[meta] => stdClass Object
(
[table] => story
[type] => item
)
[data] => stdClass Object
(
[id] => 7
[active] => 1
[blogId] => abc
[blog_heading] => xyz
)
)
==================
Log of $id :
stdClass Object
(
[active] => 1
[blog_heading] => def
[id] => 7
)
Please suggest me how can i achieve this... Anything i am doing wrong here
Please try that:
$j1 = '{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}';
$j2 = '{"blog_heading":"def"}';
$result = json_encode(
array_merge(
json_decode($j1, true),
json_decode($j2, true)
)
);
<?php
$json1='{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}';
$json2='{"blog_heading":"def"}';
$json1=json_decode($json1);
$json2=json_decode($json2);
foreach ($json1 as $key => $value) {
if($json2->$key){
$json1->$key=$json2->$key;
}
}
$json1=json_encode($json1);
$json2=json_encode($json2);
If you have only one element in array,Do like this
$a = json_decode('{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"}',true);
$b = json_decode('{"blog_heading":"def"}',true);
$a['blog_heading'] = $b['blog_heading'];
print_r($a);
If you have multiple element like this :
$c = json_decode('[{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"},
{"id":8,"active":1,"blogId":"abc","blog_heading":"xyz"}]',true);
$d = json_decode('[{"blog_heading":"def"},{"blog_heading":"hello"}]',true);
$return = array();
for ($i=0; $i < count($c); $i++) {
$c[$i]['blog_heading'] = $d[$i]['blog_heading'];
$return[] = $c[$i];
}
print_r($return);
If you want to replace value by specific id
$c = json_decode('[{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"},
{"id":8,"active":1,"blogId":"abc","blog_heading":"xyz"}]',true);
$d = json_decode('[{"id":7,"blog_heading":"def"},{"id":9,"blog_heading":"hello"}]',true);
$return = array();
for ($i=0; $i < count($c); $i++) {
if($d[$i]['id'] == $c[$i]['id']) {
$c[$i]['blog_heading'] = $d[$i]['blog_heading'];
}
$return[] = $c[$i];
}
print_r($return);
Checking dynamic key value pair :
$c = json_decode('[{"id":7,"active":1,"blogId":"abc","blog_heading":"xyz"},
{"id":8,"active":1,"blogId":"abc","blog_heading":"xyz"}]',true);
$d = json_decode('[{"id":6,"blog_heading":"def"},{"id":9,"blog_heading":"hello"}]',true);
$return = array();
for ($i=0; $i < count($c); $i++) {
$result = array_intersect_key($c[$i], $d[$i]);
foreach ($result as $key => $value) {
$c[$i][$key] = $d[$i][$key];
}
$return[] = $c[$i];
}
print_r($return);
Check demo here

How to parse the data obtained by using CURL to get DL?

I want to show list of journals and their abbreviation like:
Journal Name, Abbreviation
I am getting the data I need from :
http://images.webofknowledge.com/WOK46/help/WOS/D_abrvjt.html
So I am running the following:
$ch = curl_init();
//Set options
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'http://images.webofknowledge.com/WOK46/help/WOS/A_abrvjt.html'
));
$result = curl_exec($curl);
curl_close($curl);
$data=json_decode($result, true);
//!End function, make_call
But now what it shows me is the whole page, but as I said I only need the name of the journals(dt) and the abbreviation (dd). So How can I pars the result?
HTML DOM parsing via Simple HTML DOM
Scraping method ...
<?php
Function Scraper($file, $cnt = NULL) {
/*
#param $file, url or path/file
#param $cnt, (number of results to list) empty for all, or number
*/
require_once('PATH/TO/simple_html_dom.php');
//set_time_limit(0); // uncomment for large files
$result = array();
// Create DOM from URL
$html = file_get_html($file);
IF ($html) {
IF (empty($cnt)) { $cnt = count($html->find('DT')); }
foreach($html->find('DL') as $dl) {
for ($i = 0; $i < $cnt; $i++) {
$dt = $dl->find('DT', $i)->plaintext;
$dd = $dl->find('DD', $i)->plaintext;
$result[] = array(trim($dt) => trim($dd));
}
}
}
return $result;
}
$array = Scraper('http://somesite.com/page.html');
print_r($array);
?>
Example output ...
Array
(
[0] => Array
(
[D H LAWRENCE REVIEW] => D H LAWRENCE REV
)
[1] => Array
(
[D-D EXCITATIONS IN TRANSITION-METAL OXIDES] => SPRINGER TR MOD PHYS
)
[2] => Array
(
[DADOS-REVISTA DE CIENCIAS SOCIAIS] => DADOS-REV CIENC SOC
)
[3] => Array
(
[DAEDALUS] => DAEDALUS
)
[4] => Array
(
[DAEDALUS] => DAEDALUS-US
)
[5] => Array
(
[DAGHESTAN AND THE WORLD OF ISLAM] => SUOMAL TIED TOIM SAR
)
)
Updated example specific to user350082's issue ...
The definition lists DT and DD tags were not closed resulting in the dd being included in the find('dt') result.
<DT>D H LAWRENCE REVIEW<B><DD> D H LAWRENCE REV</B>
<DT>D-D EXCITATIONS IN TRANSITION-METAL OXIDES<B><DD> SPRINGER TR MOD PHYS</B>
etc. etc. etc.
Updated Function ...
Function Scraper($file, $cnt = NULL) {
/*
#param $file, url or path/file
#param $cnt, (number of results to list) empty for all, or number
*/
require_once('PATH/TO/simple_html_dom.php');
//set_time_limit(0); // uncomment for large files
$result = array();
// Create DOM from URL
$html = file_get_html($file);
IF ($html) {
foreach($html->find('DL') as $dl) {
IF (empty($cnt)) { $cnt = count($html->find('DT')); } // set count if null
for ($i = 0; $i < $cnt; $i++) {
$dd = $dl->find('DD', $i)->plaintext;
$dt = $dl->find('DT', $i)->innertext; // dt with html tags, easier for removing dd duplication
$dt = preg_replace('/\s+/', ' ',$dt); // remove extra whitespace, tabs etc.
// strip DD text duplication from DT
IF (($pos = strrpos($dt ,$dd)) !== false) {
$strlen = strlen($dd);
$dt = substr_replace($dt, "", $pos, $strlen);
}
$dt = strip_tags($dt); // remove html tags
IF (empty($dt)) { $dt = $dd; } // make sure dt is not empty
$result[] = array(trim($dt) => trim($dd));
}
}
}
return $result;
}

Is there an easy way to read file contents in array format in PHP?

I am trying to make use of files(.txt) to print logs. Inside the file, it logs an array value which looks like this:
Array
(
[NAME] => John Peters
[AGE] => 24
[COUNTRY] => United States
[EMAIL] => test#test.com
)
So now, I am trying to read the file contents and covert it onto an actual array so that I would be able to reference the value using the array key in a php file, something like:
echo 'Name : ' .$person['NAME'];
echo 'Age: ' .$person['AGE'];
echo 'Country: ' .$person['COUNTRY'];
echo 'Email: ' .$person['EMAIL'];
Is there a predefined php function to do it? Or how will I be able to accomplish what I want. I have tried to use the fread() and fgets() function but it doesn't really accomplish what I want or I might be missing something.
I wrote a quick script for you,
I assumed that in your (files).txt can contain many entries of print_r results e.g.
Array
(
[NAME] => John Peters
[AGE] => 24
[COUNTRY] => United States
[EMAIL] => test#test.com
)
Array
(
[NAME] => John Peters
[AGE] => 24
[COUNTRY] => United States
[EMAIL] => test#test.com
)
This script assumes that your inputs test.txt only contains array that has 1 level (so, it won't work with nested array)
$c = file_get_contents('test.txt');
# Matches all strings that has 'Array(...)' pattern
preg_match_all('#Array[^\)]+\)#', $c, $matches);
$items = array();
foreach($matches[0] as $match) {
# Extracts KEY => VAL patterns from matched text
if (preg_match_all('#\[([^\]]+)\].*?>(.*)#', $match, $array)) {
$items[] = array_combine($array[1], $array[2]);
}
}
# test your results
print_r($items);
you can read it using file_get_contents
Eg:
<?php
$homepage = file_get_contents('abc.txt');
echo $homepage;
?>
Hope it will help :)
I guess #Rezigned and I had the same idea... Here's what I came up with:
<?php
$file = file_get_contents('log.txt');
$file = preg_match_all('/(\s+\[[a-zA-Z0-9]+\]\s+=>\s+.+)\n/', $file, $lines);
$key = array();
$val = array();
foreach ($lines[0] as $line) {
$keys_vals = preg_split('/(\s+=>\s+)/', $line);
$key[] .= preg_replace('/[\[|\]]/', '', $keys_vals[0]);
$val[] .= $keys_vals[1];
}
$line_count = count($lines[0]);
for ($i = 0; $i < $line_count; $i++) {
print $key[$i] . ': ' . $val[$i];
}
There is a function shared by Matt in PHP manual called print_r_reverse, I think it's what you want. The following code is copied from PHP manual print_r function comments section directly.
<?php
function print_r_reverse($in) {
$lines = explode("\n", trim($in));
if (trim($lines[0]) != 'Array') {
// bottomed out to something that isn't an array
return $in;
} else {
// this is an array, lets parse it
if (preg_match("/(\s{5,})\(/", $lines[1], $match)) {
// this is a tested array/recursive call to this function
// take a set of spaces off the beginning
$spaces = $match[1];
$spaces_length = strlen($spaces);
$lines_total = count($lines);
for ($i = 0; $i < $lines_total; $i++) {
if (substr($lines[$i], 0, $spaces_length) == $spaces) {
$lines[$i] = substr($lines[$i], $spaces_length);
}
}
}
array_shift($lines); // Array
array_shift($lines); // (
array_pop($lines); // )
$in = implode("\n", $lines);
// make sure we only match stuff with 4 preceding spaces (stuff for this array and not a nested one)
preg_match_all("/^\s{4}\[(.+?)\] \=\> /m", $in, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
$pos = array();
$previous_key = '';
$in_length = strlen($in);
// store the following in $pos:
// array with key = key of the parsed array's item
// value = array(start position in $in, $end position in $in)
foreach ($matches as $match) {
$key = $match[1][0];
$start = $match[0][1] + strlen($match[0][0]);
$pos[$key] = array($start, $in_length);
if ($previous_key != '') $pos[$previous_key][1] = $match[0][1] - 1;
$previous_key = $key;
}
$ret = array();
foreach ($pos as $key => $where) {
// recursively see if the parsed out value is an array too
$ret[$key] = print_r_reverse(substr($in, $where[0], $where[1] - $where[0]));
}
return $ret;
}
}

generating array of parents paths of a URL

so if I have a string like this, e.g. "/path1/folder/fun/yay/"
How can I run that through a function to return an array of all the parent paths, looking like this:
array (
'/',
'/path1/',
'/path1/folder/',
'/path1/folder/fun/',
'/path1/folder/fun/yay/'
)
This is what I have so far, obviously it doesn't work and it's confusing to say the least...
$a = explode('/',$path); $ii = 0; $path_array = array();
for ($i = 0; $i < sizeof($a); $i++) {
if ($a[$i]) {
$path_array[$ii] = "";
for ($n = 0; $n < $i; $n++)
{
$path_array[$ii] .= $a[$n];
}
$ii++;
}
}
file_put_contents('text.txt',serialize($path_array));
Thanks!
BTW my end goal here is to be able to run an SQL query on a table of folder paths to increment a value on a folder and all of its parents.
Maybe there's some sort of SQL operator where I could select all rows whose path is a part of the path I input? Kinda like this in reverse:
mysqli_query($mysqli,'UPDATE content_folders SET size = size+'.filesize("content/$id").' WHERE path LIKE "'.$path.'%"')
As for the PHP function - something like this would work:
function returnAllPaths ( $fullPath = '/' , Array $pathHistory = array() )
{
while ( strlen($fullPath) > 1 AND $fullPath[0] === '/' )
{
array_push($pathHistory, $fullPath);
$fullPath = preg_replace('%(.*/)[^/]+(?:/)?$%is', '$1', $fullPath);
}
array_push($pathHistory, $fullPath);
return array_reverse($pathHistory);
}
You can use this
$path = '/path1/folder/fun/yay/';
$path = explode('/',$path);
$path = array_filter($path);
$iniVal = '';
$array_paths = array();
array_push($array_paths,'/');
foreach($path as $array){
$value = $iniVal.'/'.$array.'/';
array_push($array_paths,$value);
$iniVal .= '/'.$array;
}
//print_r($array_paths);
Output would display in array such as :
Array ( [0] => / [1] => /path1/ [2] => /path1/folder/ [3] => /path1/folder/fun/ [4] => /path1/folder/fun/yay/ )
same as
array (
'/',
'/path1/',
'/path1/folder/',
'/path1/folder/fun/',
'/path1/folder/fun/yay/'
)
DEMO : PHP FIDDLE

How do I redistribute an array into another array of a certain "shape". PHP

I have an array of my inventory (ITEMS A & B)
Items A & B are sold as sets of 1 x A & 2 x B.
The items also have various properties which don't affect how they are distributed into sets.
For example:
$inventory=array(
array("A","PINK"),
array("A","MAUVE"),
array("A","ORANGE"),
array("A","GREY"),
array("B","RED"),
array("B","BLUE"),
array("B","YELLOW"),
array("B","GREEN"),
array("B","BLACK")
);
I want to redistribute the array $inventory to create $set(s) such that
$set[0] => Array
(
[0] => array(A,PINK)
[1] => array(B,RED)
[2] => array(B,BLUE)
)
$set[1] => Array
(
[0] => array(A,MAUVE)
[1] => array(B,YELLOW)
[2] => array(B,GREEN)
)
$set[2] => Array
(
[0] => array(A,ORANGE)
[1] => array(B,BLACK)
[2] => NULL
)
$set[3] => Array
(
[0] => array(A,GREY)
[1] => NULL
[2] => NULL
)
As you can see. The items are redistributed in the order in which they appear in the inventory to create a set of 1 x A & 2 x B. The colour doesn't matter when creating the set. But I need to be able to find out what colour went into which set after the $set array is created. Sets are created until all inventory is exhausted. Where an inventory item doesn't exist to go into a set, a NULL value is inserted.
Thanks in advance!
I've assumed that all A's come before all B's:
$inventory=array(
array("A","PINK"),
array("A","MAUVE"),
array("A","ORANGE"),
array("A","GREY"),
array("B","RED"),
array("B","BLUE"),
array("B","YELLOW"),
array("B","GREEN"),
array("B","BLACK")
);
for($b_start_index = 0;$b_start_index<count($inventory);$b_start_index++) {
if($inventory[$b_start_index][0] == 'B') {
break;
}
}
$set = array();
for($i=0,$j=$b_start_index;$i!=$b_start_index;$i++,$j+=2) {
isset($inventory[$j])?$temp1=$inventory[$j]:$temp1 = null;
isset($inventory[$j+1])?$temp2=$inventory[$j+1]:$temp2 = null;
$set[] = array( $inventory[$i], $temp1, $temp2);
}
To make it easier to use your array, you should make it something like this
$inv['A'] = array(
'PINK',
'MAUVE',
'ORANGE',
'GREY'
);
$inv['B'] = array(
'RED',
'BLUE',
'YELLOW',
'GREEN',
'BLACK'
);
This way you can loop through them separately.
$createdSets = $setsRecord = $bTemp = array();
$bMarker = 1;
$aIndex = $bIndex = 0;
foreach($inv['A'] as $singles){
$bTemp[] = $singles;
$setsRecord[$singles][] = $aIndex;
for($i=$bIndex; $i < ($bMarker*2); ++$i) {
//echo $bIndex.' - '.($bMarker*2).'<br/>';
if(empty($inv['B'][$i])) {
$bTemp[] = 'null';
} else {
$bTemp[] = $inv['B'][$i];
$setsRecord[$inv['B'][$i]][] = $aIndex;
}
}
$createdSets[] = $bTemp;
$bTemp = array();
++$bMarker;
++$aIndex;
$bIndex = $bIndex + 2;
}
echo '<pre>';
print_r($createdSets);
print_r($setsRecord);
echo '</pre>';
To turn your array into an associative array, something like this can be done
<?php
$inventory=array(
array("A","PINK"),
array("A","MAUVE"),
array("A","ORANGE"),
array("A","GREY"),
array("B","RED"),
array("B","BLUE"),
array("B","YELLOW"),
array("B","GREEN"),
array("B","BLACK")
);
$inv = array();
foreach($inventory as $item){
$inv[$item[0]][] = $item[1];
}
echo '<pre>';
print_r($inv);
echo '</pre>';
Maybe you can use this function, assuming that:
... $inventory is already sorted (all A come before B)
... $inventory is a numeric array staring at index zero
// $set is the collection to which the generated sets are appended
// $inventory is your inventory, see the assumptions above
// $aCount - the number of A elements in a set
// $bCount - the number of B elements in a set
function makeSets(array &$sets, array $inventory, $aCount, $bCount) {
// extract $aItems from $inventory and shorten $inventory by $aCount
$aItems = array_splice($inventory, 0, $aCount);
$bItems = array();
// iterate over $inventory until a B item is found
foreach($inventory as $index => $item) {
if($item[0] == 'B') {
// extract $bItems from $inventory and shorten $inventory by $bCount
// break out of foreach loop after that
$bItems = array_splice($inventory, $index, $bCount);
break;
}
}
// append $aItems and $bItems to $sets, padd this array with null if
// less then $aCount + $bCount added
$sets[] = array_pad(array_merge($aItems, $bItems), $aCount + $bCount, null);
// if there are still values left in $inventory, call 'makeSets' again
if(count($inventory) > 0) makeSets($sets, $inventory, $aCount, $bCount);
}
$sets = array();
makeSets($sets, $inventory, 1, 2);
print_r($sets);
Since you mentioned that you dont have that much experience with arrays, here are the links to the php documentation for the functions I used in the above code:
array_splice — Remove a portion of the array and replace it with something else
array_merge — Merge one or more arrays
array_pad — Pad array to the specified length with a value
This code sorts inventory without any assumption on inventory ordering. You can specify pattern (in $aPattern), and order is obeyed. It also fills lacking entries with given default value.
<?php
# config
$aInventory=array(
array("A","PINK"),
array("A","MAUVE"),
array("A","ORANGE"),
array("A","GREY"),
array("B","RED"),
array("B","BLUE"),
array("B","YELLOW"),
array("B","GREEN"),
array("B","BLACK"),
array("C","cRED"),
array("C","cBLUE"),
array("C","cYELLOW"),
array("C","cGREEN"),
array("C","cBLACK")
);
$aPattern = array('A','B','A','C');
$mDefault = null;
# preparation
$aCounter = array_count_values($aPattern);
$aCurrentCounter = $aCurrentIndex = array_fill_keys(array_unique($aPattern),0);
$aPositions = array();
$aFill = array();
foreach ($aPattern as $nPosition=>$sElement){
$aPositions[$sElement] = array_keys($aPattern, $sElement);
$aFill[$sElement] = array_fill_keys($aPositions[$sElement], $mDefault);
} // foreach
$nTotalLine = count ($aPattern);
$aResult = array();
# main loop
foreach ($aInventory as $aItem){
$sElement = $aItem[0];
$nNeed = $aCounter[$sElement];
$nHas = $aCurrentCounter[$sElement];
if ($nHas == $nNeed){
$aCurrentIndex[$sElement]++;
$aCurrentCounter[$sElement] = 1;
} else {
$aCurrentCounter[$sElement]++;
} // if
$nCurrentIndex = $aCurrentIndex[$sElement];
if (!isset($aResult[$nCurrentIndex])){
$aResult[$nCurrentIndex] = array();
} // if
$nCurrentPosition = $aPositions[$sElement][$aCurrentCounter[$sElement]-1];
$aResult[$nCurrentIndex][$nCurrentPosition] = $aItem;
} // foreach
foreach ($aResult as &$aLine){
if (count($aLine)<$nTotalLine){
foreach ($aPositions as $sElement=>$aElementPositions){
$nCurrentElements = count(array_keys($aLine,$sElement));
if ($aCounter[$sElement] != $nCurrentElements){
$aLine = $aLine + $aFill[$sElement];
} // if
} // foreach
} // if
ksort($aLine);
# add empty items here
} // foreach
# output
var_dump($aResult);
Generic solution that requires you to specify a pattern of the form
$pattern = array('A','B','B');
The output will be in
$result = array();
The code :
// Convert to associative array
$inv = array();
foreach($inventory as $item)
$inv[$item[0]][] = $item[1];
// Position counters : int -> int
$count = array_fill(0, count($pattern),0);
$out = 0; // Number of counters that are "out" == "too far"
// Progression
while($out < count($count))
{
$elem = array();
// Select and increment corresponding counter
foreach($pattern as $i => $pat)
{
$elem[] = $inv[ $pat ][ $count[$i]++ ];
if($count[$i] == count($inv[$pat]))
$out++;
}
$result[] = $elem;
}

Categories