json_encode not working as expected using array source - php

In my php I am reading a file and successfully getting each row into an array ($line[1] because its a 3 column CSV and I just need the 2nd value):
while (($line = fgetcsv($file, 1000)) !== false)
{
$course[] = array('course' => $line[1]);
}
$course[] correctly contains the array like:
0 =>
array (size=1)
'course' => string 'Course One' (length=68)
1 =>
array (size=1)
'course' => string 'Course Two' (length=45)
Problem is I cannot get the array to convert to json using json_encode
$json_res = json_encode($course);
EDIT: So just to be clear, I have array like this
2 =>
array (size=1)
'course' => string 'Associate Degree of Business Studies' (length=36)
3 =>
array (size=1)
'course' => string 'Associate Degree of Business Administration' (length=43)
$json_encode , gives me
boolean false

ok after taking in consideration all the information you provided, your original code should work. Try this out and let me know if it works.
$file = new SplFileObject("file.csv");
$file->setFlags(SplFileObject::READ_CSV);
$course = array();
foreach ($file as $row) {
$line = array('course' => $row[1]);
array_push($course, $line);
}
$json_res = json_encode($course);
var_dump($json_res);
Update: Try this code and let me know if it works:
$file = fopen('file.csv', 'r');
$course = array();
while (($data = fgetcsv($file, 1000, ",")) !== FALSE) {
$line = array('course' => utf8_decode($data[1]));
array_push($course, $line);
}
$json_res = json_encode($course);
var_dump($json_res)
;

Related

Convert CSV string row with no delimiters into an array

So I'm attempting to explode my string of csv rows into an array and I'm having a difficult time.
Let me lead you through the steps:
var_dump($line); returns an string as this: :string 'TEST Test Test2 Test3
Now, when I have an .txt file, and I call $arr = explode("\t", $line);, the $arr returns an array
array (size=15)
0 => string 'TEST ' (length=11)
1 => string 'Test' (length=4)
2 => string 'Test 2' (length=0)
3 => string 'Test 3' (length=6)
But if I have an .csv file, and I attempt to explode it, I get left with an array string as such:
array (size=1)
0 => string 'TEST Test Test2 Test3'
I tried doing the following but I'm not having much luck: $test = str_getcsv($line, "\t", '', ''); - All the examples for str_getcsv show it like this:
$str = "the,cat,in,the,hat";
$arr = str_getcsv($str);
print_r($arr);
But mine aren't comma separated, but instead all tabbed.
All help would be appreciated.
If you're using a file to get the csv's you should be able to use fgetcsv for this read more here.
$filename = "";
if (($handle = fopen($filename, "r")) !== false) {
while (($line = fgetcsv($handle, 0, "\t")) !== false) {
// $data should be an array of all the items in here.
print_r($line);
}
}

How to filter a date using filter_var_array

I have a csv file that contains lines with a format as follows:
Name;timestamp;floatValue
The file has over than 20000 lines, and I want to filter each value of each line. I tried using this code :
$args=array(FILTER_SANITIZE_STRING,FILTER_VALIDATE_INT,FILTER_VALIDATE_FLOAT);
while (($line = fgetcsv($handle, 1024, ";")) !== FALSE) {
$testing = filter_var_array($line,$args);
var_dump($testing);
}
I get this error:
filter_var_array(): Numeric keys are not allowed in the definition array
So I have 2 problems here:
Why do I get this error ? In fact, as I can't get from the line an array with keys and values, I don't know how to still use the filter_var_array
How to combine filtering strings, floats with a date ? is it possible to skip the date in the middle to filter it after separetly by using DateTime::CreateFromFormat ? I checked this doc but there is no filter for dates.
:::EDIT:::
What about this:
$data = array(
'name' => $line[0],
'timestamp' => $line[1],
'value' => $line[2]);
$args=array(
'name' => FILTER_SANITIZE_STRING,
'timestamp' => FILTER_VALIDATE_INT,
'value' => FILTER_VALIDATE_FLOAT);
$testing = filter_var_array($data,$args);
var_dump($testing);
Kindly tell me if it's a good approche.
filter_var_array works with associative arrays, not numeric,
you have to transform your arrays by adding associative keys
$args = array('string' => FILTER_SANITIZE_STRING, 'int' => FILTER_VALIDATE_INT, 'float' => FILTER_VALIDATE_FLOAT);
$keys = array('string', 'int', 'float');
while (($line = fgetcsv($handle, 1024, ";")) !== FALSE) {
$testing = filter_var_array(array_combine($keys, $line), $args);
var_dump($testing);
}

Searching for numbers with a comma as a decimal point in an array

I have to search through an Excel file and get the numbers that have a comma as a decimal point and convert it to a decimal point.(ex: 23,56 -> 23.56, 23123,566 -> 23123.566). I have already exported the excel file to .csv and put all contents into arrays but I have trouble finding the numbers with comma.
This is how one of my array looks like:
Array
(
[A1] => 1
[A2] => 123123
[A3] => dasdadwa
[A4] => 6,7
[A5] => 24f,5
[A6] => f5,5
[A7] => dasdad,fsdfsdfsfsasada dasdasd
[A8] => aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[A9] => dasdasd
[A10] => q231e
[A11] =>
[A12] => 0
[A13] =>
[A14] =>
[A15] => 1
[A16] => 123123
[A17] => dasdadwa
[A18] => 6,7
[A19] => 24f,5
[A20] => f5,5
[A21] => dasdad,fsdfsdfsfsasada dasdasd
[A22] =>
[A23] =>
[A24] => q231e
[A25] =>
[A26] => 0
[A27] =>
[A28] =>
[A29] => 1
[A30] => 123123
[A31] => dasdadwa
[A32] => 6,7
[A33] => 24f,5
[A34] => f5,5
[A35] => dasdad,fsdfsdfsfsasada dasdasd
[A36] =>
[A37] =>
[A38] => q231e
[A39] =>
[A40] =>
[A41] =>
[A42] =>
)
I'm only interested in the characters that have only numbers and a comma but it is troublesome because those entries are strings. I have tried messing with regex but I just could not get it to work.
Here is what i have so far:
function csv_to_array($filename='', $delimiter=',')
{
if(!file_exists($filename) || !is_readable($filename))
return FALSE;
$header = NULL;
$data = array();
if (($handle = fopen($filename, 'r')) !== FALSE)
{
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE)
{
if(!$header)
$header = $row;
else
$data[] = array_combine($header, $row);
}
fclose($handle);
}
return $data;
}
$contents = csv_to_array($filename.'.csv');
foreach($contents as $val)
{
//If $val is a number separated by comma
//Replace comma with . (str_replace(',','.');, $val);)
}
Just simple pattern which will replace only your pattern:
//rest od your code and now:
foreach($contents as $key => $val)
{
$contents[$key] = preg_replace('/^(\d+),(\d+)$/', '\1.\2', $val);
}
This code will touch only strings like 2,3. Strings like this ff,333 will not be touch
Since you would like to extract only decimals, I suggest using regex, like this:
foreach($contents as $val) {
// if $val is a number separated by comma
if (preg_match('/^[0-9]+,[0-9]+$/', $val) == 1) {
// transform into float with two decimals and dot as decimal separator
$float = number_format($val, 2, '.');
}
}
Edit: updated regex pattern following comments.
Like this?
foreach($contents as $val)
{
if (strpos($val, ',') !== false) {
$val = str_replace(',', '.', $val);
}
}

What do I need for doing this regex or split?

I have strings like the following that I have to split:
Other,CODSITE,Items::getCodCdeCli+Address::getNameAddress
Other,CODSITE,Items::getCodCdeCli
Items::getCode+Address::getName,CODSITE+Items::getSample,Items::getItemID
Other, CODSITE, CODSITE2
Into:
array(
array(
0 => 'Other',
1 => 'CODSITE',
2 => array(
'Items' => 'getCodCdeCli',
'Address' => 'getNameAddress'
)
),
//...
)
Each comma involve new information, if we have a '+' we need to append both data. If we have '::' we need to get first part as key of the result information.
For beginning this solution I have tried to split this on comma:
$re = "/([^,]+)/";
$str = "Other,CODSITE,Items::getCodCdeCli+Address::getNameAddress";
preg_match_all($re, $str, $matches);
for now with this regex I have this:
array (size=2)
0 =>
array (size=3)
0 => string 'Other' (length=5)
1 => string 'CODSITE' (length=7)
2 => string 'Items::getCodCdeCli+Address::getNameAddress' (length=43)
1 =>
array (size=3)
0 => string 'Other' (length=5)
1 => string 'CODSITE' (length=7)
2 => string 'Items::getCodCdeCli+Address::getNameAddress' (length=43)
Which is wrong. I have same result twice.. and line 2 => [...] is not split (which is normal with my regex)
One way of doing it in single pass is by using array_combine function like this:
$str = 'Other,CODSITE,Items::getCodCdeCli+Address::getNameAddress';
if ( preg_match_all('~(?|[,+]([^,+]+)::([^,+]+)|([^,]+))~', $str, $m) )
print_r( array_combine ( $m[1], $m[2] ) );
Output:
Array
(
[Other] =>
[CODSITE] =>
[Items] => getCodCdeCli
[Address] => getNameAddress
)
Does it need to be regex? It might be possible to achieve this with a couple of explodes and foreach loops:
$str = 'Other,CODSITE,Items::getCodCdeCli+Address::getNameAddress';
//new entry per comma (,)
$results = explode(',',$str);
//check each entry for array information
foreach($results as &$result) {
if(strpos($result,'+') !== FALSE) {
//explode array information
$bits1 = explode('+',$result);
$result = array();
foreach($bits1 as &$subresult) {
//format array information into key => value pairs
if(strpos($subresult,'::') !== FALSE) {
$bits = explode('::',$subresult);
$result[$bits[0]] = $bits[1];
}
}
}
}
var_dump($results);
/**
* array (size=3)
* 0 => string 'Other' (length=5)
* 1 => string 'CODSITE' (length=7)
* 2 => array (size=2)
* 'Items' => string 'getCodCdeCli' (length=12)
* 'Address' => string 'getNameAddress' (length=14)
*/
With the help of #Richard Parnaby-King answer. This is the solution, in fact no regex is needed even if i'm sure we can use it for the same result.
$lines = array(
0 => 'Other,CODSITE,Items::getCodCdeCli+Address::getNameAddress',
2 => 'Other,CODSITE,Items::getCodCdeCli',
3 => 'Items::getCode+Address::getName,CODSITE+Items::getSample,Items::getItemID',
4 => 'Other, CODSITE, CODSITE2',
);
foreach ($lines as $input) {
$informations = explode(',', $input);
$result = array();
foreach ($informations as $information) {
if(strpos($information, '+') !== FALSE) {
$classes = explode('+',$information);
$temp = array();
foreach($classes as $subresult) {
if(strpos($subresult,'::') !== FALSE) {
$classAndMethod = explode('::',$subresult);
$temp[$classAndMethod[0]] = $classAndMethod[1];
} else {
$temp[] = trim($subresult);
}
}
$result[] = $temp;
} elseif (strpos($information, '::') !== FALSE) {
$classAndMethod = explode('::',$information);
$result[][$classAndMethod[0]] = $classAndMethod[1];
} else {
$result[] = trim($information);
}
}
var_dump($result);
}
It works !

How to change the keys/first row in this CSV library import Codeigniter

class CSVReader {
var $fields; /** columns names retrieved after parsing */
var $separator = ';'; /** separator used to explode each line */
var $enclosure = '"'; /** enclosure used to decorate each field */
var $max_row_size = 4096; /** maximum row size to be used for decoding */
function parse_file($p_Filepath) {
$file = fopen($p_Filepath, 'r');
$this->fields = fgetcsv($file, $this->max_row_size, $this->separator, $this->enclosure);
$keys_values = explode(',',$this->fields[0]);
$content = array();
$keys = $this->escape_string($keys_values);
$i = 1;
while( ($row = fgetcsv($file, $this->max_row_size, $this->separator, $this->enclosure)) != false ) {
if( $row != null ) { // skip empty lines
$values = explode(',',$row[0]);
if(count($keys) == count($values)){
$arr = array();
$new_values = array();
$new_values = $this->escape_string($values);
for($j=0;$j<count($keys);$j++){
if($keys[$j] != ""){
$arr[$keys[$j]] = $new_values[$j];
}
}
$content[$i]= $arr;
$i++;
}
}
}
fclose($file);
return $content;
}
function escape_string($data){
$result = array();
foreach($data as $row){
$result[] = str_replace('"', '',$row);
}
return $result;
}
}
In this is the code of the library for importing csv files to sql is the key is in the first row. I want to remove the first row keys in csv file and add it to this code.
Fields in first row of csv that I want to be in the already in the code:
$fields = array( '0' => 'model',
'1' => 'serial_num' ,
'2' => 'client_name',
'3' => 'end_user',
'4' => 'trends_warranty_start',
'5' => 'trends_warranty_end',
'6' => 'trends_warranty_period',
'7' => 'client_contract_no',
'8' => 'vendor',
'9' => 'support_coverage',
'10' => 'sla',
'11' => 'service_contract_num',
'12' => 'support_coverage_start',
'13' => 'support_coverage_end',
'14' => 'support_coverage_period',
'15' => 'trends_po',
'16' => 'supplier_so');
Instead of making change in the code you can simply add these columns in the first row of csv file. And the will be available in the code.
"serial_num" ,"client_name","end_user","trends_warranty_start","trends_warranty_end","trends_warranty_period","client_contract_no","vendor","support_coverage","sla","service_contract_num","support_coverage_start","support_coverage_end","support_coverage_period","trends_po","supplier_so"
The other possibel scanrio is that when you get csv result add column names in the result array like this
$result = $this->csvreader->parse_file('Test.csv');
$columns = array(
'model',
'serial_num' ,
'client_name',
'end_user',
'trends_warranty_start',
'trends_warranty_end',
'trends_warranty_period',
'client_contract_no',
'vendor',
'support_coverage',
'sla',
'service_contract_num',
'support_coverage_start',
'support_coverage_end',
'support_coverage_period',
'trends_po',
'supplier_so'
);
$resultWithColumns = array_unshift($result , $columns);
And now you have column names in the result array.

Categories