Concatenating PHP strings from an iteration - php

I'm working on some Database functions and, for some reason, I made two functions to make simple inserts/selects with arrays passed as arguments to a php function. The problem starts here.
// basic database functions, to aid the development :D
static public function Insert($table, $items = array())
{
if(is_array($items) == false)
{
return false;
}
$header = 'INSERT INTO ' . $table . '(';
$values = 'VALUES(';
$count = count($items) - 1;
$cur = 0;
foreach($items as $key => $value)
{
$num = is_numeric($value);
$header .= $key . ($cur < $count) ? ', ' : ' ';
$values .= (($num) ? '' : '\'') . $value . (($num) ? '' : '\'') . (($cur < $count) ? ', ' : '');
$cur ++;
}
$header .= ')';
$values .= ')';
self::Query($header . $values);
}
$pair = array('id' => null,
'name' => Database::EscapeString((string)$xml->ID),
'avatar_url' => Database::EscapeString((string)$xml->Avatar),
'personal_msg' => Database::EscapeString((string)$xml->AboutMe),
'level' => (int)$xml->Level,
'progress' => (int)$xml->Progress,
'trophies_total' => (int)$xml->Trophies->Total,
'trophies_platinum' => (int)$xml->Trophies->Platinum,
'trophies_gold' => (int)$xml->Trophies->Gold,
'trophies_silver' => (int)$xml->Trophies->Silver,
'trophies_bronze' => (int)$xml->Trophies->Bronze,
'country' => Database::EscapeString((string)$xml->Country->Culture),
'is_plus' => (string)$xml->Plus,
'points' => (int)$xml->LevelData->Points,
'floor' => (int)$xml->LevelData->Floor,
'ceiling' => (int)$xml->LevelData->Ceiling,
'game_completion' => (double)$xml->GameCompletion,
'background_color' => ((int)$xml->Background->R << 16) | ((int)$xml->Background->G << 8) | ((int)$xml->Background->B),
'jid' => (string)$xml->jid
);
Insert('profiles', $pair);
The data that the query contains is not correct:
INSERT INTO profiles(, , , , , , , , , , , , , , , , , , , )VALUES('', 'AlmamuPP', 'http://static-resource.np.community.playstation.net/avatar/3RD/30004.png', 'EVE Online & DUST fan', 2, 17, 12, 0, 0, 6, 6, 'ES', 'false', 270, 200, 600, 12.5, 458759, 'AlmamuPP#a4.es.np.playstation.net')
As you may notice, it just ignores all the keys in the dictionary, but the funny fact is that if I add
echo $key;
in the foreach the keys are printed as they should... Any idea about what could be hapening there and a way to fix it?

You are missing parenthesis:
$header .= $key . (($cur < $count) ? ', ' : ' ');
Like this it will work.

Related

How to reduce the nested foreaches for a 5-levels deep array

I have a PHP tree structure (array max depth: 5):
$arr = array(
'31' => array(
'Amsterdam' => array(),
'Rotterdam' => array(),
'Den Haag' => array(),
'Utrecht' => array(),
'Eindhoven' => array(),
'Tilburg' => array(),
'Almere' => array(
'036' => array(
'BU00340212' => array(
'name' => 'Muziekwijk Noord',
'residents' => array(
'Henk',
'Dirk',
'Jaap',
),
),
'BU00340213' => array(
'name' => 'Muziekwijk Zuid',
'residents' => array(
'Wim',
'Pim',
'Jim',
'Tim',
),
),
)
),
'Groningen' => array(),
'Breda' => array(),
'Nijmegen' => array(),
)
);
I would like to have this output:
Almere(netnummer: 036)(cbscode: BU00340212): Henk
Almere(netnummer: 036)(cbscode: BU00340212): Dirk
Almere(netnummer: 036)(cbscode: BU00340212): Jaap
Almere(netnummer: 036)(cbscode: BU00340213): Wim
Almere(netnummer: 036)(cbscode: BU00340213): Pim
Almere(netnummer: 036)(cbscode: BU00340213): Jim
Almere(netnummer: 036)(cbscode: BU00340213): Tim
So I did some coding by myself. The code below produces the output that I want.
foreach($arr as $unitKey => $citySet){
foreach($citySet as $cityName => $cityData){
if($cityName === 'Almere'){
$almere = $citySet[$cityName];
foreach($almere as $netnummer => $netData){
foreach($netData as $cbsCode => $data){
foreach($data['residents'] as $residents){
echo $cityName . '(netnummer: '. $netnummer .')(cbscode: '. $cbsCode .'): ' . $residents . '<br>';
}
}
}
}
}
}
The code displayed above makes use of 5 foreaches, and I'm doubting if that's a good idea. So I tried to reduce a couple foreaches like this:
$arrB = $arr['31']['Almere']['036'];
foreach($arrB as $k => $netData){
foreach($netData as $field => $fieldData){
if($field === 'residents') {
foreach($fieldData as $resident){
echo 'Almere(netnummer: 036)(cbscode: '. $k .'): ' . $resident . '<br>';
}
}
}
}
The code displayed above makes use of 3 foreaches. That is because it doesn't traverse the full tree.
I want to traverse the full tree with 1 foreach, and produce the output I was aiming for. So I was thinking about RecursiveArray in combination with RecursiveIteratorIterator, but I can't get the cbscode if I use this approach. See for yourself:
$recursiveArrayIterator = new RecursiveArrayIterator($arr);
$recursiveIteratorIterator = new RecursiveIteratorIterator($recursiveArrayIterator);
foreach($recursiveIteratorIterator as $k => $v){
if($k !== 'name'){
echo 'Almere(netnummer: 036)(cbscode: ???): ' . $v . '<br>';
}
}
Q1: is this possible to traverse the tree structure with one foreach with the shown output?
Q2:if it is possible, can you show the code? if not, is it possible to reduce the amount of used foreaches to 2?
-- Edit --
Q (rephrased): What is most readable way to fully traverse an 5 level deep array?
You can short this down to:
$arrB = $arr['31']['Almere']['036'];
foreach($arrB as $code => $val) {
if (isset($val["residents"])) {
$prefix = 'Almere(netnummer: 036)(cbscode: '. $code .'): ';
echo $prefix . implode('<br>' . $prefix, $val["residents"]) . '<br>';
}
}
Live example: 3v4l
I invested some time in this problem, and came with a functional programming approach:
function recursive($data, $countryCode = null, $countryData = null, $city = null, $cityData = null, $netNummer = null, $netData = null, $cbscode = null, $cbsData = null, $residents = null){
if($residents){
$resident = array_shift($residents);
echo $city . '(netnummer: ' . $netNummer . ')(cbscode: ' . $cbscode .'): ' . $resident . '<br>';
if($residents){
recursive($data, $countryCode, $countryData, $city, $cityData, $netNummer, $netData, $cbscode, $cbsData, $residents);
}
return null;
}
if($cbscode && $cbsData){
$residents = $cbsData['residents'];
recursive($data, $countryCode, $countryData, $city, $cityData, $netNummer, $netData, $cbscode, $cbsData, $residents);
}
if($countryCode && $countryData && $netData){
$cbscode = key($netData);
$cbsData = array_shift($netData);
recursive($data, $countryCode, $countryData, $city, $cityData, $netNummer, $netData, $cbscode, $cbsData);
}
if($countryCode && $countryData && $city && $cityData){
$netNummer = key($cityData);
$netData = array_shift($cityData);
recursive($data, $countryCode, $countryData, $city, $cityData, $netNummer, $netData);
}
if($countryCode && $countryData){
$city = key($countryData);
$cityData = array_shift($countryData);
recursive($data, $countryCode, $countryData, $city, $cityData);
}
if($data){
$countryCode = key($data);
$countryData = array_shift($data);
if($countryData){
recursive($data, $countryCode, $countryData);
}
}
return null;
}
recursive($arr);
Online source: https://3v4l.org/rsf5o

How to create a file based on Database Values?

I want to create a .INI file based on the values I get from database.
This are the values in my database for :
Now in the field parameter filed is the value i want to write in file each in new line.
I fetch the values like this:
$this->data['params'] = $this->parameter_m->get();
So I get all the values from the table.
I want to write values in file like this:
[INIDetails]
SipUserName=
Password=
Domain=
Proxy=
Port=
SipAuthName=
DisplayName=
ServerMode=
UCServer=
UCUserName=
UCPassword=
[DialPlan]
DP_Exception=
DP_Rule1=
DP_Rule2=
[Advanced]
OperationMode=
MutePkey=
Codec=
PTime=
AudioMode=
SoftwareAEC=
EchoTailLength=
PlaybackBuffer=
CaptureBuffer=
JBPrefetchDelay=
JBMaxDelay=
SipToS=
RTPToS=
LogLevel=
I have WRITE Function that writes into file
function write($file = NULL, $file_content = array(), $sections = TRUE) {
$this->file_content = (!empty($file_content)) ? $file_content : $this->file_content;
$this->file = ($file) ? $file : $this->file;
$this->sections = $sections;
$content = NULL;
if ($this->sections) {
foreach ($this->file_content as $section => $file_content) {
$content .= '[' . $section . ']' . PHP_EOL;
foreach ($file_content as $key => $val) {
if (is_array($val)) {
foreach ($val as $v) {
$content .= $key . '[]=' . (is_numeric($v) ? $v : $v ) . PHP_EOL;
}
} elseif (empty($val)) {
$content .= $key . '=' . PHP_EOL;
} else {
$content .= $key . '=' . (is_numeric($val) ? $val : $val ) . PHP_EOL;
}
}
$content .= PHP_EOL;
}
} else {
foreach ($this->file_content as $key => $val) {
if (is_array($val)) {
foreach ($val as $v) {
$content .= $key . '[] = ' . (is_numeric($v) ? $v : '"' . $v . '"') . PHP_EOL;
}
} elseif (empty($val)) {
$content .= $key . ' = ' . PHP_EOL;
} else {
$content .= $key . ' = ' . (is_numeric($val) ? $val : '"' . $val . '"') . PHP_EOL;
}
}
}
return (($handle = fopen($this->file, 'w+')) && fwrite($handle, trim($content)) && fclose($handle)) ? TRUE : FALSE;
}
And i use that function like this :
$path = "./uploads/";
$filename = "default.ini";
$this->load->helper('file');
$file = $path.$filename;
$this->load->library('ini');
$ini = new INI($file);
$ini->write($file, $this->data['params']);
So i how to write the array of values i get from database into file ?
As you can see there is a filed called Parameter_Type i want to set it as section in INI file.
I'm guessing that your parameter_m is your model which have get() function where it returns array values from your table. What I think, the problem is that your model return incorrect structure of your array. Your array should have structure like:
array(
"parameter_type" => array(
"parameter" => value
)
)
in your model's get function, there should be something like:
class parameter_m extends CI_Model {
public function get()
{
$query = $this->db->get('your_parameter_table');
$assoc_arr = array();
foreach ($query->result() as $row)
{
$assoc_arr[$row->parameter_type][$row->parameter] = '';
}
return $assoc_arr;
}
}
Using the get() it should output:
array(
"INIDetails" => array(
"SipUserName" => '',
"Password" => '',
"Domain" => '',
"Proxy" => '',
"Port" => '',
"SipAuthName" => '',
"DisplayName" => '',
"ServerMode" => '',
"UCServer" => '',
"UCUserName" => '',
"UCPassword" => ''
),
"DialPlan" => array(
"DP_Exception" => '',
"DP_Rule1" => '',
"DP_Rule2" => ''
),
"Advanced" => array(
"OperationMode" => '',
"MutePkey" => '',
"Codec" => '',
"PTime" => '',
"AudioMode" => '',
"SoftwareAEC" => '',
"EchoTailLength" => '',
"PlaybackBuffer" => '',
"CaptureBuffer" => '',
"JBPrefetchDelay" => '',
"JBMaxDelay" => '',
"SipToS" => '',
"RTPToS" => '',
"LogLevel" => ''
)
);

how can i use more than one array in foreach()?

i want to send more than on array in foreach() .
i know this way is false .whats the true method ?
$Fname = [1,2,3,4,5];
$Lname = [1,2,3,4,5];
$Addrs = [1,2,3,4,5];
$Mobile = [1,2,3,4,5];
$fields = array(
'name' => 'a',
'type' => 'b',
'value' => 'n',
'show' => 'd',
);
foreach($fields as $key => $n)
{
echo " {$Fname[$key]} , {$Lname[$key]},{$Addrs[$key]} , {$Mobile[$key]},{$key} ,{$n} <br>";
}
If all your arrays have the same number of rows, you can use a for loop instead of a foreach, in conjunction with next() and current() for associative array:
for( $i = 0; $i < count($Fname); $i++ )
{
echo $Fname[$i] . PHP_EOL;
echo $Lname[$i] . PHP_EOL;
echo $Addrs[$i] . PHP_EOL;
echo $Mobile[$i] . PHP_EOL;
echo current($fields) . PHP_EOL;
next($fields);
}
The problem is that your arrays haven't same rows number...
So you have to add some condition like this:
for( $i = 0; $i < count($Fname); $i++ )
{
echo $Fname[$i] . PHP_EOL;
echo $Lname[$i] . PHP_EOL;
echo $Addrs[$i] . PHP_EOL;
echo $Mobile[$i] . PHP_EOL;
if( isset(current($fields)) )
{
echo current($fields) . PHP_EOL;
next($fields);
}
}
i know this way is false...? What's false about it?
foreach() will iterate over an array, not over multiple arrays.... if you absolutely need to iterate over multiple arrays within the same foreach() loop, you can use SPL's MultipleIterator, but it adds a lot more complexity to your code, and the approach that you've taken is as good as any
Just make sure that your keys match up in all the arrays; if they don't then you will have problems
foreach(array_values($fields) as $key => $n)
{
$k = array_keys($fields)[$key];
echo " {$Fname[$key]} , {$Lname[$key]},{$Addrs[$key]} , {$Mobile[$key]},{$k} ,{$n} <br>";
}
Instead of storing your data like that, it'd be easier to store it in an array of associative arrays:
$people = array(
array(
'firstName' => 'Bruce',
'lastName' => 'Wayne',
'address' => '123 East St. Gotham City, XX USA'
'mobile' => '847-847-8475'
),
array(
'firstName' => 'Roland',
'lastName' => 'Deschain',
'address' => 'N/A'
'mobile' => '191-919-1919'
)
);
foreach($people as $person){
echo $person['firstName'] + ', ' + $person['lastName'];
echo $person['address'] + ', ' + $person['mobile'];
}
It's just a cleaner way to store/access your data, makes it easy to use one foreach as well.
Try this code
$arr1 = array("a" => 1, "b" => 2, "c" => 3);
$arr2 = array("x" => 4, "y" => 5, "z" => 6);
foreach ($arr1 as $key => &$val) {}
foreach ($arr2 as $key => $val) {}
var_dump($arr1);
var_dump($arr2);

How to Export data from 3 tables in one .csv file php

I want to export the data from the 3 tables without joins in one .csv file.
I am trying with joins but i am not getting the result Which i want.
Below are my table structure
Playlist Songs Rating
CODE
$mysql_host = DB_HOST;
$mysql_user = DB_USER;
$mysql_pass = DB_PASSWORD;
$mysql_db = DB_NAME;
$pre = $wpdb->prefix;
$link = mysql_connect($mysql_host, $mysql_user, $mysql_pass) or die('Could not connect: ' . mysql_error());
mysql_select_db($mysql_db, $link) or die('Could not select database: ' . $mysql_db);
$query = "SELECT plist.*, psong.*, prate.*
FROM " . $pre . "foo_playlists As plist
LEFT JOIN " . $pre . "foo_songs As psong
On plist.playlist_name = psong.splaylist_name
LEFT JOIN " . $pre . "foo_rating As prate
On psong.song_id = prate.rsong_id";
$result = mysql_query($query);
$row = mysql_fetch_assoc($result);
$line = "";
$comma = "";
foreach ($row as $name => $value) {
$line .= $comma . '"' . str_replace('"', '""', $name) . '"';
$comma = ",";
}
$line .= "\n";
$out = $line;
mysql_data_seek($result, 0);
while ($row = mysql_fetch_assoc($result)) {
$line = "";
$comma = "";
foreach ($row as $value) {
$line .= $comma . '"' . str_replace('"', '""', $value) . '"';
$comma = ",";
}
$line .= "\n";
$out.=$line;
}
$csv_file_name = 'songs_' . date('Ymd_His') . '.csv'; # CSV FILE NAME WILL BE table_name_yyyymmdd_hhmmss.csv
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename=" . $csv_file_name);
header("Content-Description:File Transfer");
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Type: application/octet-stream');
echo __($out, "foo");
exit;
I got this result with I want this desired result
How can I do this?
Well, your problem is that you can't retrieve all the data at the same time in an only MySQL query, as they are not related data. Your problem is just the output, so, you only will have to relate the 3 set of results in an only array. To do that:
Execute the three querys, and save them in three unrelated arrays.
Relate them with a key you'll share with all of them.
Loop over all the arrays assigning values to a main "output" one.
With that, you'll have the array which you can output to get the CSV you want. For the sake of the example, and due I can't write a valid code with your vars and queries, I wrote the following example. It has the 3 different arrays you'll have to get from your database with mock data, but you can grab the idea. Just copy and paste and you'll have the live example:
<?php
$playlists = array(
array(
'id' => 1
, 'data' => 'playlist1'
)
, array(
'id' => 2
, 'data' => 'playlist2'
)
, array(
'id' => 3
, 'data' => 'playlist3'
)
);
$songs = array(
array(
'id' => 1
, 'data' => 'song1'
)
, array(
'id' => 2
, 'data' => 'song2'
)
, array(
'id' => 3
, 'data' => 'song3'
)
, array(
'id' => 4
, 'data' => 'song4'
)
, array(
'id' => 5
, 'data' => 'song5'
)
);
$rates = array(
array(
'id' => 1
, 'data' => 'rating1'
)
, array(
'id' => 2
, 'data' => 'rating2'
)
, array(
'id' => 3
, 'data' => 'rating3'
)
, array(
'id' => 4
, 'data' => 'rating4'
)
, array(
'id' => 5
, 'data' => 'rating5'
)
, array(
'id' => 6
, 'data' => 'rating6'
)
);
// Count all the arrays and get the bigger:
$num = 0;
$play_num = count( $playlists );
$num = ($play_num > $num) ? $play_num : $num;
$song_num = count( $songs );
$num = ($song_num > $num) ? $song_num : $num;
$rate_num = count( $rates );
$num = ($rate_num > $num) ? $rate_num : $num;
$output = array();
for ( $i = 0; $i<=$num; $i++ ) {
$output[] = array(
'id_playlist' => !empty( $playlists[$i]['id'] ) ? $playlists[$i]['id'] : ''
, 'data_playlist' => !empty( $playlists[$i]['data'] ) ? $playlists[$i]['data'] : ''
, 'id_song' => !empty( $songs[$i]['id'] ) ? $songs[$i]['id'] : ''
, 'data_song' => !empty( $songs[$i]['data'] ) ? $songs[$i]['data'] : ''
, 'id_rate' => !empty( $rates[$i]['id'] ) ? $rates[$i]['id'] : ''
, 'data_rate' => !empty( $rates[$i]['data'] ) ? $rates[$i]['data'] : ''
);
}
foreach ( $output as $out ) {
echo implode( ' - ', $out);
echo '<br>';
}
Output:
1 - playlist1 - 1 - song1 - 1 - rating1
2 - playlist2 - 2 - song2 - 2 - rating2
3 - playlist3 - 3 - song3 - 3 - rating3
- - 4 - song4 - 4 - rating4
- - 5 - song5 - 5 - rating5
- - - - 6 - rating6

Imploding with "and" in the end?

I have an array like:
Array
(
[0] => Array
(
[kanal] => TV3+
[image] => 3Plus-Logo-v2.png
)
[1] => Array
(
[kanal] => 6\'eren
[image] => 6-eren.png
)
[2] => Array
(
[kanal] => 5\'eren
[image] => 5-eren.png
)
)
It may expand to several more subarrays.
How can I make a list like: TV3+, 6'eren and 5'eren?
As array could potentially be to further depths, you would be best off using a recursive function such as array_walk_recursive().
$result = array();
array_walk_recursive($inputArray, function($item, $key) use (&$result) {
array_push($result, $item['kanal']);
}
To then convert to a comma separated string with 'and' separating the last two items
$lastItem = array_pop($result);
$string = implode(',', $result);
$string .= ' and ' . $lastItem;
Took some time but here we go,
$arr = array(array("kanal" => "TV3+"),array("kanal" => "5\'eren"),array("kanal" => "6\'eren"));
$arr = array_map(function($el){ return $el['kanal']; }, $arr);
$last = array_pop($arr);
echo $str = implode(', ',$arr) . " and ".$last;
DEMO.
Here you go ,
$myarray = array(
array(
'kanal' => 'TV3+',
'image' => '3Plus-Logo-v2.png'
),
array(
'kanal' => '6\'eren',
'image' => '6-eren.png'
),
array(
'kanal' => '5\'eren',
'image' => '5-eren.png'
),
);
foreach($myarray as $array){
$result_array[] = $array['kanal'];
}
$implode = implode(',',$result_array);
$keyword = preg_replace('/,([^,]*)$/', ' & \1', $implode);
echo $keyword;
if you simply pass in the given array to implode() function,you can't get even the value of the subarray.
see this example
assuming your array name $arr,codes are below
$length = sizeof ( $arr );
$out = '';
for($i = 0; $i < $length - 1; $i ++) {
$out .= $arr [$i] ['kanal'] . ', ';
}
$out .= ' and ' . $arr [$length - 1] ['kanal'];
I think it would work to you:
$data = array(
0 =>['kanal' => 'TV1+'],
1 =>['kanal' => 'TV2+'],
2 =>['kanal' => 'TV3+'],
);
$output = '';
$size = sizeof($data)-1;
for($i=0; $i<=$size; $i++) {
$output .= ($size == $i && $i>=2) ? ' and ' : '';
$output .= $data[$i]['kanal'];
$output .= ($i<$size-1) ? ', ' : '';
}
echo $output;
//if one chanel:
// TV1
//if two chanel:
// TV1 and TV2
//if three chanel:
// TV1, TV2 and TV3
//if mote than three chanel:
// TV1, TV2, TV3, ... TV(N-1) and TV(N)
$last = array_slice($array, -1);
$first = join(', ', array_slice($array, 0, -1));
$both = array_filter(array_merge(array($first), $last));
echo join(' and ', $both);
Code is "stolen" from here: Implode array with ", " and add "and " before last item
<?php
foreach($array as $arr)
{
echo ", ".$arr['kanal'];
}
?>

Categories