I'm trying to process an uploaded CSV file into an array in PHP. I have that working fine, but some files from users end up have a bunch of blank rows with delimiters. This usually happens when they use Excel on an existing file. Highlighting the old cells and just clearing them.
Sample CSV File
lineNo,date,vendor,amount
1,5/2/2012,V000236,3727.21
2,5/2/2012,V003432,4826.19
,,,
,,,
Becomes the following array
Array
(
[0] => Array
(
[0] => lineNo
[1] => date
[2] => vendor
[3] => amount
)
[1] => Array
(
[0] => 1
[1] => 5/2/2012
[2] => V000236
[3] => 3727.21
)
[2] => Array
(
[0] => 2
[1] => 5/2/2012
[2] => V003432
[3] => 4826.19
)
[3] => Array
(
[0] =>
[1] =>
[2] =>
[3] =>
)
[4] => Array
(
[0] =>
[1] =>
[2] =>
[3] =>
)
)
I don't want to just remove any blank rows, I want to stop after array index 2. Go easy on my function I'm new :P
function csvToArray($csvFile, $specialChars = FALSE) {
$arrayCSV = array();
if (($csvHandle = fopen($csvFile, "r")) !== FALSE) { // Open the CSV
$csvKey = 0; // Set the parent array key to 0
while (($csvData = fgetcsv($csvHandle)) !== FALSE) {
$c = count($csvData); // Count the total keys in each row
//need something to stop on blank delimiter rows ,,,
for ($x = 0; $x < $c; $x++) { //Populate the array
if ($specialChars === TRUE) {
$arrayCSV[$csvKey][$x] = htmlspecialchars($csvData[$x]);
} else {
$arrayCSV[$csvKey][$x] = $csvData[$x];
}
}
$csvKey++;
}
fclose($csvHandle);
}
return $arrayCSV;
}
Ultimately, I'd like this returned
Array
(
[0] => Array
(
[0] => lineNo
[1] => date
[2] => vendor
[3] => amount
)
[1] => Array
(
[0] => 1
[1] => 5/2/2012
[2] => V000236
[3] => 3727.21
)
[2] => Array
(
[0] => 2
[1] => 5/2/2012
[2] => V003432
[3] => 4826.19
)
)
Can't you break; your while loop as soon as you find an empty value?
if (($csvHandle = fopen($csvFile, "r")) !== FALSE) { // Open the CSV
$csvKey = 0; // Set the parent array key to 0
while (($csvData = fgetcsv($csvHandle)) !== FALSE) {
$c = count($csvData); // Count the total keys in each row
// ## Flag variable ##########
$empty = true;
for ($x = 0; $x < $c; $x++) { //Populate the array
// ## Test each value ##########
$empty = $empty && (empty($csvData[$x]));
if ($specialChars === TRUE) {
$arrayCSV[$csvKey][$x] = htmlspecialchars($csvData[$x]);
} else {
$arrayCSV[$csvKey][$x] = $csvData[$x];
}
}
// ## Stop loop if all empty ##########
if ($empty) {
unset($arrayCSV[$csvKey]);
break;
}
$csvKey++;
}
fclose($csvHandle);
}
Note:
A blank line in a CSV file will be returned as an array comprising a single null field, and will not be treated as an error.
if ($c == 1 && current($csvData) === null) {
break;
}
You can run a extra loop for checking empty
while(! feof($file)){
$current_data = fgetcsv($file);
for ($i=0; $i < $total_title ; $i++) {
if( empty( $current_data[ $i ] ) ){
unset($information[$itt]);
break;
}
$information[$itt][ $titles[$i] ] = $current_data[$i] ;
}
$itt = $itt+1;
}
I recommend this php function that does exactly what you want
http://www.php.net/manual/es/function.file.php
Related
I'm having a peculiar issue. I have a CSV file that has Comma Separated Values that I need to upload and then get Nested Array of values based on following 3 conditions;
The array will first loop through all values and get first 4 unique
characters. (Codes)
Match each column values with the with number of
columns in each row and give count of rows that matches 4 digit
codes. (Single_Devices for single column and Dual, Triple and Quad for respective columns count)
Match each column values with code and list all the
columns under the Devices. (Numbers)
CSV file
123429000000000
123429000000001
123429000000010,123429000000011
123429000000040,123429000000041
What I desire is;
Array
(
[Code] => 1234
(
[single_devices] => 2
(
[0] => Array
(
[0] => 123429000000000
)
[1] => Array
(
[0] => 123429000000001
)
)
[dual_devices] => 2
(
[0] => Array
(
[0] => 123429000000010
[1] => 123429000000011
)
[1] => Array
(
[0] => 123429000000040
[1] => 123429000000041
)
)
)
)
Is it possible?
I can manage JSON converted data or object or just associative nested array.
Edit: This is the code I wrote for which was only showing values and not indexes as I desired.
// Get all numbers in array
for ($j = 0; $j < count($csv_file[$i]); $j++){
$numbers[] = $csv_file[$i][$j];
}
// Get codes from numbers
for ($i = 0; $i < count($csv_file); $i++){
for ($j = 0; $j < count($csv_file[$i]); $j++){
$codes[] = substr($csv_file[$i][$j], 0, 4);
}
}
// Get unique codes from codes array
$codes = array_unique($codes);
// Get numbers and sort them codes and device count wise.
for ($i = 0; $i < count($csv_file); $i++){
for ($j = 0; $j < count($csv_file[$i]); $j++){
$q = count($csv_file[$i]); // set device count based on column count
if (count($csv_file[$i]) == $q){ // if device count is equal to column count
foreach ($codes as $code){ // loop through unique codes
if ($code == substr($csv_file[$i][$j], 0, 4)){ // if number's first 4 char matches code
// create array with code and then device count and add numbers
$devices[$code][$q.'_device_numbers'][$i][$j] = preg_replace('/\s+/', '', $csv_file[$i][$j]);
}
}
}
}
}
This is what I am getting from the above code.
Array
(
[1234] => Array
(
[1_sim_imeis] => Array
(
[0] => Array
(
[0] => 123429000000000
)
[1] => Array
(
[0] => 123429000000001
)
)
[2_sim_imeis] => Array
(
[2] => Array
(
[0] => 123429000000010
[1] => 123429000000011
)
[3] => Array
(
[0] => 123429000000040
[1] => 123429000000041
)
)
)
)
This is based on reading the file as a csv (using fgetcsv()) and extracting the first 4 digits of the first value on each line. It then uses another array to give the key for the 'single_devices' etc. key - using the count of the number of elements on the line (-1 as the array is 0 based)...
$fileName = "a.dat";
$output = [];
$baseData = [ 'single_devices', 'dual_devices', 'triple_devices', 'quad_devices' ];
$fh = fopen ( $fileName, "r" );
while ( ($data = fgetcsv($fh)) !== false ) {
$code = substr($data[0], 0, 4);
$output[$code][$baseData[count($data)-1]][] = $data;
}
fclose($fh);
print_r($output);
which with the test data gives...
Array
(
[1234] => Array
(
[single_devices] => Array
(
[0] => Array
(
[0] => 123429000000000
)
[1] => Array
(
[0] => 123429000000001
)
)
[dual_devices] => Array
(
[0] => Array
(
[0] => 123429000000010
[1] => 123429000000011
)
[1] => Array
(
[0] => 123429000000040
[1] => 123429000000041
)
)
)
With
while ( ($data = fgetcsv($fh)) !== false ) {
$code = substr($data[0], 0, 4);
if ( !isset($output[$code])) {
$output[$code] = ["code" => $code];
}
$deviceLabel = $baseData[count($data)-1];
$output[$code][$deviceLabel]['count'] =
($output[$code][$deviceLabel]['count'] ?? 0) + 1;
$output[$code][$deviceLabel][] = $data;
}
you can get an output of...
Array
(
[1234] => Array
(
[code] => 1234
[single_devices] => Array
(
[count] => 2
[0] => Array
(
[0] => 123429000000000
)
[1] => Array
(
[0] => 123429000000001
)
)
I have tried array_merge and array_unique but it couldn't helped me out.
Here is my code:
public function syncContacts() {
$data['data'] = $this->main_manager->select_all('users'); # get all user data
$info[0] = [
"contact_name" => "a",
"number" => "031651651"
];
$info[1] = [
"contact_name" => "b",
"number" => "+923402382972"
];
$info[2] = [
"contact_name" => "c",
"number" => "31651651"
];
$info[3] = [
"contact_name" => "d",
"number" => "6165165123323"
];
$info[4] = [
"contact_name" => "e",
"number" => "316516512113"
];
for ($i = 0; $i < count($info); $i++) { # info array loop
if (substr($info[$i]['number'], 0, 1) == "+") { # finds + sign in numbers
for ($x = 0; $x < count($data['data']); $x++) { # user data array loop
if (
$info[$i]['number'] == $data['data'][$x]['country_code'] . $data['data'][$x]['phone_number'] # first condition
|| $info[$i]['number'] == $data['data'][$x]['country_code'] . 0 . $data['data'][$x]['phone_number'] # second condition
) {
$finalData['data']['registered'][$i]['name'] = $info[$i]['contact_name'];
$finalData['data']['registered'][$i]['number'] = $info[$i]['number'];
} else {
$finalData['data']['unregistered'][$i]['name'] = $info[$i]['contact_name'];
$finalData['data']['unregistered'][$i]['number'] = $info[$i]['number'];
$result = array_unique(array_merge($finalData['data']['unregistered'][$i], $info[$i]));
//
}
} # end of user data array loop
} else { # finds 0 in numbers
for ($x = 0; $x < count($data['data']); $x++) { # user data array loop
if (
$info[$i]['number'] == $data['data'][$x]['phone_number'] # first condition
|| 0 . $info[$i]['number'] == $data['data'][$x]['phone_number'] # second condition
|| $info[$i]['number'] == 0 . $data['data'][$x]['phone_number'] # third condition
) {
$finalData['data']['registered'][$i]['name'] = $info[$i]['contact_name'];
$finalData['data']['registered'][$i]['number'] = $info[$i]['number'];
} else {
$finalData['data']['unregistered'][$i]['name'] = $info[$i]['contact_name'];
$finalData['data']['unregistered'][$i]['number'] = $info[$i]['number'];
$result = array_unique(array_merge($finalData['data']['unregistered'][$i], $info[$i]));
// $result = array_merge($finalData['data']['unregistered'][$i], $info[$i]);
// $finalData['data']['unregistered'][$i] = array_unique($result);
}
} # end of user data array loop
}
} #end of info array loop
print_r($finalData);
die();
}
I am making a sync contacts webservice.
In $data array I am getting data from users table and I have 8 record in it.
3 record matched from my given array which is $info and two are unmatched. I made an array which is $finalData['data'].
I have to separate the record in registered and unregistered key of $finalData array. I have separated matched numbers in registered key of an array but couldn't separate the correct unmatched numbers in unregistered key of the array.
I am getting this result:
Array
(
[data] => Array
(
[unregistered] => Array
(
[0] => Array
(
[name] => a
[number] => 031651651
)
[1] => Array
(
[name] => b
[number] => +923402382972
)
[2] => Array
(
[name] => c
[number] => 31651651
)
[3] => Array
(
[name] => d
[number] => 6165165123323
)
[4] => Array
(
[name] => e
[number] => 316516512113
)
)
[registered] => Array
(
[0] => Array
(
[name] => a
[number] => 031651651
)
[1] => Array
(
[name] => b
[number] => +923402382972
)
[2] => Array
(
[name] => c
[number] => 31651651
)
)
)
)
Match index of first array with another and unset the matched index and then you will get the unregistered numbers.
How about using a hash like array? See example here http://php.net/manual/en/language.types.array.php
I have this array where I need to remove any item where inTOC is 0 (ie. false) while keeping the index to be able to loop using for.
This is the array:
Array
(
[0] => Array
(
[name] => JAL
[id] => 798162f0-d779-46b6-96cb-ede246bf4f3f
[inTOC] => 1
[children] => Array
(
[0] => Array
(
[name] => BRU
[id] => 5600b395-4a28-4956-ccbf-9b238c4fa432
[inTOC] => 0
)
[1] => Array
(
[name] => TEW
[id] => 9e2ebbf6-1c81-4ff7-feb5-c5bede2ccd6c
[inTOC] => 1
)
)
)
[1] => Array
(
[name] => ABC
[id] => 761e1909-34b3-4733-aab6-ebef26d3fcb9
[inTOC] => 1
)
)
This is the function I have so far where I tried unset which doesn't rebase and array_splice which only removes a child node when the goal is to remove the array:
public function tocFilterNonTOC($tree){
$size = count($tree);
for ($i = 0; $i < $size; $i++) {
if ($tree[$i]['inTOC']) {
$this->tocFilterNonTOC($tree[$i]['children']);
} else {
array_splice($tree[$i], $i, 1); // removes the 'name' node (BRU) only
}
}
}
In the end, I went back to using unset but added array_values to the recursive function like so:
public function tocFilterNonTOC($tree){
$size = count($tree);
for ($i = 0; $i < $size; $i++) {
if ($tree[$i]['inTOC']) {
$this->tocFilterNonTOC($tree[$i]['children']);
} else {
unset($tree[$i]);
}
}
if ($tree!=null && is_array($tree)) $tree = array_values($tree)
}
Having some difficulty trying to do this. I'm fetching an array of all submissions, and they are being returned in an array like this:
Array
(
[0] => Array
(
[Submission] => Array
(
[user_id] => 2
[title] => This is a test, only a test
[source] => http://www.testing.com
[slug] => this-is-a-test-only-a-test
[category] => misc
[created] => 2012-10-05 03:43:11
[id] => 110
)
[SubmissionsVote] => Array
(
[0] => Array
(
[id] => 336
[user_id] => 2
[submission_id] => 110
[vote_type] => up
)
)
(
[1] => Array
(
[id] => 337
[user_id] => 4
[submission_id] => 110
[vote_type] => down
)
)
)
)
My intent is to loop through that returned array, and grab all the SubmissionsVote by vote_type == up and vote_type == down.
I then want to calculate a score (this example would return a score of 0 which is just: up - down. With that, I want to put that score into an array and append it to the end of the original one so it'd look like:
Array
(
[0] => Array
(
[Submission] => Array
(
[user_id] => 2
[title] => This is a test, only a test
[source] => http://www.testing.com
[slug] => this-is-a-test-only-a-test
[category] => misc
[created] => 2012-10-05 03:43:11
[id] => 110
)
[SubmissionsVote] => Array
(
[0] => Array
(
[id] => 336
[user_id] => 2
[submission_id] => 110
[vote_type] => up
)
)
(
[1] => Array
(
[id] => 337
[user_id] => 4
[submission_id] => 110
[vote_type] => down
)
)
[SubmissionScore] => Array
(
[0] => 0
)
)
)
Here is what I am doing unsuccessfully:
$votes = array();
$totalScore = array();
foreach ($submissions as $submission) {
$vote = $submission['SubmissionsVote'];
array_push($votes, $vote);
}
for ($i = 0; $i < count($votes); $i++) {
$downVotes = 0;
$upVotes = 0;
if ($votes[$i]['vote_type'] == 'down') {
$downVotes += 1;
} else if ($votes[$i]['vote_type'] == 'up') {
$upVotes += 1;
}
$score = $upVotes - $downVotes;
$totalScore = array_push($totalScore, $score);
}
Would love to get a little push in the right direction here.
Try this one:
$newSubmissions = array();
foreach ($submissions as $submission) {
$SubmissionsVote = $submission['SubmissionsVote'];
foreach($SubmissionsVote as $votes) {
$score = 0;
if ($votes['vote_type'] == 'down') {
$score -= 1;
} else if ($votes['vote_type'] == 'up') {
$score += 1;
}
$submission['SubmissionScore'] = array($score);
}
$newSubmissions[] = $submission;
}
$submissions = $newSubmissions;
I see at least two errors in your code :
You never set SubmissionScore in your array to $totalScore value.
Even if you add a $votes[$i]['SubmissionScore'] = $totalScore, that will not work, in PHP only object are passed by reference so $votes will only contain copy.
There are multiple possibility to resolve the problem but a reference in the foreach is a good choice :
foreach ($submissions as &$submission) {
$totalScore = 0;
foreach ($submission['SubmissionsVote'] as $vote) {
if ($vote['vote_type'] == 'down') {
$totalScore--;
} else if ($vote['vote_type'] == 'up') {
$totalScore++;
}
}
$submission['SubmissionScore'] = $totalScore;
}
Each submission will now have a SubmissionScore based on up/down vote.
You are initializing $downVotes and $upVotes inside a loop, that means you override values each time you iterate through the array.
Anyway, you could simplify this.
foreach ($submissions as $index => $submission) {
$up = 0;
$down = 0;
foreach ($submission['SubmissionsVote'] as $vote) {
if ($vote['vote_type'] == 'up') {
$up++;
} else {
$down++;
}
}
$submissions[$index]['SubmissionScore'] = $up - $down;
}
i have an array like:
Array ( [0] => #!A1#DC [1] => #IMSR102.71/74.82 [2] => #HV50 [3] => #PR7/7/ [4] => #RX0 [5] => #ERN/1//0 [6] => #Q2 [7] => #!A1#DC [8] => #IMSR102.50/74.82 [9] => #HV40 [10] => #PR5/5/ [11] => #RX0 [12] => #ERN/1//1 [13] => #Q2 etc etc with hundreds o values
i get this array from a file (with the function file($filename) ) and i need to split it in many subarray.
"!A1#DC" this is the beginning of a series of values that ends with #Q2 but the number of the values between the beginning and the end is not always the same and the only 2 values that are same are the two given ("!A1#DC" for the beginning and "#Q2" for the end)
how can i get somethings like this?
Array (
[0] => Array ( [0] => #!A1#DC [1] => #IMSR102.71/74.82 [2] => #HV50 [3] => #PR7/7/ [4] => #RX0 [5] => #ERN/1//0 [6] => #Q2 )
[1] => Array (
[1] => #!A1#DC [2] => #IMSR102.50/74.82 [3] => #HV40 [4] => #PR5/5/ [5] => #RX0 [6] => #ERN/1//1 [7] => #Q2 etc etc
could you please help me?
thanks
Loop through an array. When you meet starting value, store it's index. When you meet ending value, use array_slice() to extract the part between the last pair of starting and ending values, store this part into another array.
$source = array (
'#!A1#DC',
'#IMSR102.71/74.82',
'#HV50',
'#PR7/7/',
'#RX0',
'#ERN/1//0',
'#Q2',
'#!A1#DC',
'#IMSR102.50/74.82',
'#HV40',
'#PR5/5/',
'#RX0',
'#ERN/1//1',
'#Q2',
);
$dest = array();
$startValue = '#!A1#DC';
$endValue = '#Q2';
$startIndex = 0;
foreach ( $source as $index => $value ) {
if ( $value === $startValue ) {
$startIndex = $index;
} else
if ( $value === $endValue ) {
$dest[] = array_slice($source, $startIndex, $index - $startIndex + 1);
}
}
print_r($dest);
Basically you need to loop through each element of $input, collecting those within START and END elements into a separate array:
$input = array("#!A1#DC", "A", "B", "#Q2");
$values = array();
$current = 0;
define("START", "#!A1#DC");
define("END", "#Q2");
for ($i = 0; $i < count($input); $i++) {
if ($input[$i] == END) {
// Ignore any elements after this point until we see START
$current = null;
} else if ($input[$i] == START) {
// Create a new current collection array
$current = count($values);
$values[$current] = array();
} else {
// Store the value if we are collecting
if ($current !== null) {
$values[$current][] = $input[$i];
}
}
}