I have a CSV file containing two rows of data, one which the user will input and the other will be returned. e.g. inputting a post/zipcode which will be found in the CSV file, the data in the next cell should be returned.
<?php
function csv_to_array($filename='bn.csv', $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;
}
function search($data, $x) {
for($i = 0; $i < sizeof($data); $i++) {
if($data[$i] == $x) return $i;
}
return -1;
}
$data = array("bn.csv");
echo search($data, "BN1 1AA");
print_r(csv_to_array('bn.csv'));
?>
Currently I am just getting -1 returned, what should I do?
Thanks in advance.
$data = array("bn.csv"); creates an array with the literal string bv.csv in it. I'm guessing you want $data = csv_to_array("bn.csv"); here instead. I would build an associative array like this:
$data = [
'BN1 1AA' => 'E05002432',
'...' => '...',
'...' => '...',
];
Via something like:
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
$data[$row[0]] = $row[1];
}
Thus, you can refer to an entry directly by its key, you don't need to iterate over every item to search for a match:
$search = 'BN1 1AA';
if (array_key_exists($search, $data)) {
echo $data[$search];
} else {
echo "not found";
}
There are several problems towards the end of your code.
In search() - you are trying to match the postcode with the entire row in $data[$i] == $x, $data[$i] is actually a list of the fields in the row, so perhaps matching it with ($data[$i][$field] == $x) and $field is the field name of the postcode.
You were calling search() with an array of the file names for the data and not the data from the file, so this code calls csv_to_array() first and passes the result to search()...
Lastly - the sample data didn't have BN1 1AA in it anyway, so should return -1.
function search($data, $x, $field = 'Postcode') {
for($i = 0; $i < sizeof($data); $i++) {
if ($data[$i][$field] == $x)
return $i;
}
return -1;
}
$data = csv_to_array('a.csv');
print_r($data);
echo search($data, "BN1 1AD");
Related
I need to find and replace all the values of rows of a CSV using PHP;
I am trying this but its replacing even the headers to 0 and row values are not doubling as it suppose to.
public function checkForNumericValues()
{
// Read the columns and detect numeric values
if (($this->handle = fopen($this->csvFile, "r")) !== FALSE)
{
$fhandle = fopen($this->csvFile,"r");
$content = fread($fhandle,filesize($this->csvFile));
while (($this->data = fgetcsv($this->handle, 1000, ",")) !== FALSE)
{
$this->num = count($this->data);
// Skipping the header
if($this->row == 1)
{
$this->row++;
continue;
}
$this->row++;
// Check and replace the numeric values
for ($j=0; $j < $this->num; $j++)
{
if(is_numeric($this->data[$j]))
{
$content = str_replace($this->data[$j], $this->data[$j] * 2, $content);
}
else
{
$content = str_replace($this->data[$j], 0, $content);
}
}
break;
// print_r($content);
}
$fhandle = fopen($this->csvFile,"w");
fwrite($fhandle,$content);
fclose($this->handle);
}
echo "Numeric and String values been changed in rows of the CSV!";
}
CSV is like this:
You shouldn't update the entire $contents when you're processing each field in the CSV, just update that field. Your str_replace() will replace substrings elsewhere in the file; for instance, if the current field contains 5, you'll replace all the 5's in the file with 10, so 125 will become 1210.
You can do it correctly by replacing the element in the $this->data array. After you do that, you can then join them back into a string with implode(). Then you can keep all the updated lines in a string, which you write back to the file at the end.
You can skip the header line by calling fgets() before the while loop.
public function checkForNumericValues()
{
// Read the columns and detect numeric values
if (($this->handle = fopen($this->csvFile, "r")) !== FALSE)
{
$output = "";
$output .= fgets($this->csvFile); // Copy header line to output
while (($this->data = fgetcsv($this->handle, 1000, ",")) !== FALSE)
{
$this->num = count($this->data);
// Check and replace the numeric values
for ($j=0; $j < $this->num; $j++)
{
if(is_numeric($this->data[$j]))
{
$this->data[$j] *= 2;
}
else
{
$this->data[$j] = 0;
}
}
$output .= implode(',', $this->data) . "\n";
}
fclose($this->handle);
$fhandle = fopen($this->csvFile,"w");
fwrite($fhandle,$output);
fclose($fhandle);
}
echo "Numeric and String values been changed in rows of the CSV!";
}
I've been struggling with this PHP problem for a while now. I have a csv file with client info which looks like this.
clientName, clientNumber, clientStatus
Name1,123456,1
Name2,123457,0
now, the problem is the following. sometimes the csv has a date of birth too...as follows :
clientName, clientNumber, clientDOB, clientStatus
Name1,123456,01/10/1980,1
Name2,123457,1980-10-01,0
as you can see the dates are in different format. Whilst converting the csv into an array, i need to check if the in the csv there is clientDOB, and if yes, format it to mysql.
function dateToMysql($date) {
$mysqlDate = date("Y-m-d",strtotime(str_replace('/','-',$date)));
return $mysqlDate;
}
function csvToArray($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, 10000, $delimiter)) !== FALSE) {
if(!$header) {
$header = $row;
} else {
if (in_array("clientDOB", $header)) {
//echo dateToMysql($header['clientDOB'][$row])."<br>";
$data[] = dateToMysql(array_combine($header, $row));
} else {
$data[] = array_combine($header, $row);
}
}
}
fclose($handle);
}
return $data;
}
echo "<pre>";
print_r(csvToArray($_FILES['csvFile']['name']));
echo "</pre>";
Any help would be appreciated. Thank you
Here's an updated function:
function csvToArray($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, 10000, $delimiter)) !== FALSE) {
$row = array_map('trim', $row);
if (!$header)
$header = $row;
else
{
$row = array_combine($header, $row);
if ( isset( $row[ 'clientDOB' ] ) )
$row[ 'clientDOB' ] = date('Y-m-d', strtotime( $row[ 'clientDOB' ] ) );
$data[] = $row;
}
}
fclose($handle);
}
return $data;
}
Notable changes:
$row = array_map('trim', $row) makes sure there's no surrounding spaces around the names and values, otherwise the ['clientDOB'] won't match (because it's [' clientDOB'].
changing the value of $row['clientDOB'] before appending the $row to $data. Your dateToMysql function expects a $date but instead it was passed an associative array.
using strtotime no replacing is needed: it can handle both date formats.
Well, basically what this code does is grab some links from a source code of a website and send them to an mp3 player.
The big problem is on the get_link function, where i want to store the urls to an array. The section where im having problems is commented.
Sorry for posting all this code but the functions are connected to each others.
function getHost($db,$id){
if(isset($_GET['id'])){
$sql1 = "SELECT host FROM mixtape WHERE id=?";
$stm = $db->prepare($sql1);
$stm->execute(array($id));
$row1 = $stm->fetch(PDO::FETCH_ASSOC);
if($row1['host']=='host1'){
$sql2 = "SELECT link1 FROM faixa WHERE id_mixtape IN(SELECT id FROM mixtape WHERE id=?)";
$stm = $db->prepare($sql2);
$stm->execute(array($id));
$rows_affected = $stm->rowCount();
$array=array();
if (count($rows_affected) > 0) {
for($i=1; $i <= $rows_affected; $i++) {
$row2 = $stm->fetch(PDO::FETCH_ASSOC);
$url=$row2['link1'];
get_Link($db,$url,$i,$rows_affected,$array);
}
}
}
}
}
function get_Link($db,$url,$pos,$rows_affect,$array){
$find = 'url:';
$reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
$data = file_get_contents($url);
$data = explode("\n", $data);
for ($line = 0; $line < count($data); $line++) {
if (strpos($data[$line], $find) !== false) {
$link = preg_replace($reg_exUrl,"", $data[$line]);
$v[]=$link;
}
}
if($pos!=$rows_affect-1){
$url="mylink.com/".$link."|";
}else{
$url="mylink.com/".$link."&";
}
$array[$pos]=$url;
var_dump($array); // Here says that are 3 values in the array. True
if($pos==$rows_affect-1){
var_dump($array); // Here is only showing the last value in the array. Why?
player($db,$array);
}
}
function player($db,$array){
if(isset($_GET['id'])){
foreach($array as $i=>$item){
echo $item;
}
}
}
This piece of code:
$c=0;
for ($line = 0; $line < count($data); $line++) {
if (strpos($data[$line], $find) !== false) {
$link = preg_replace($reg_exUrl,"", $data[$line]);
$v[$c]=$link;
}
}
Should be like:
$c=0;
for ($line = 0; $line < count($data); $line++) {
if (strpos($data[$line], $find) !== false) {
$link = preg_replace($reg_exUrl,"", $data[$line]);
$v[$c]=$link;
$c = $c+1; //this is missing or $c++;
}
}
OR:
for ($line = 0; $line < count($data); $line++) {
if (strpos($data[$line], $find) !== false) {
$link = preg_replace($reg_exUrl,"", $data[$line]);
$v[]=$link; //That way works too
}
}
Miguelfsf, you must first learn about variable scope.
Your problem is, you created the $array=array() (the $array show be the $row2).
You declared a new variable, but you didn't used, the $array was just to tell you, declare your array that way
$row2=array().
After that you need to do
$row2[] = $stm->fetch(PDO::FETCH_ASSOC);
Why?
Because the assoc returns a associative array, then it will do
$array => {title => "last title} = $newData => {title => "new title"}
It will replace the value
Using the [] everytime you do this it'll create a new element.
Then
{
0 => { title => "title1"}
1 => { title => "title2"}
2 => { title => "title3"}
3 => { title => "title4"}
}
The .csv file:
question1,question2,question3,question4,question5,question6,question7,question8,question9,question10
yes,response,response,response,response,response,response,response,response,response
yes,response2,response2,response2,response2,response2,response2,response2,response2,response2
no,response3,response3,response3,response3,response3,response3,response3,response3,response3
I want to get this result in php.
$question = "the_question_goes_here"
question1
yes = 2
no = 1
The code must find the unique responses for each question and count how many of each.
Can anyone help?
str_getcsv() can be used to get a csv string as an array.
Using this you can write a loop over the array which counts up values (in pseudocode):
counts = array;
//Loop over each row
for(row in csvrows){
for(cell in row){
counts[rowHeader][cellValue] = counts[rowHeader][cellValue]+1;
}
}
This should do the trick reading the file contents into PHP
$data= array();
$row = 1;
if (($handle = fopen("test.csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
foreach ($data as $position => $value) {
if($row == 1) {
$data[$position]['question'] = $value;
$data[$position]['yes'] = 0;
$data[$position]['no'] = 0;
continue;
}
if ($value == 'yes') {
$data[$position]['yes'] = $data[$position]['yes'] + 1
} elseif ($value == 'no') {
$data[$position]['no'] = $data[$position]['no'] + 1
}
}
$row++;
}
fclose($handle);
}
This will return a array which you can read like this
Array value
'question' key holding text
'yes' key holding numOf yes
'no'key holding numOf no
I would like to convert a CSV to Json, use the header row as a key, and each line as object. How do I go about doing this?
----------------------------------CSV---------------------------------
InvKey,DocNum,CardCode
11704,1611704,BENV1072
11703,1611703,BENV1073
---------------------------------PHP-----------------------------------
if (($handle = fopen('upload/BEN-new.csv'. '', "r")) !== FALSE) {
while (($row_array = fgetcsv($handle, 1024, ","))) {
while ($val != '') {
foreach ($row_array as $key => $val) {
$row_array[] = $val;
}
}
$complete[] = $row_array;
}
fclose($handle);
}
echo json_encode($complete);
Just read the first line separately and merge it into every row:
if (($handle = fopen('upload/BEN-new.csv', 'r')) === false) {
die('Error opening file');
}
$headers = fgetcsv($handle, 1024, ',');
$complete = array();
while ($row = fgetcsv($handle, 1024, ',')) {
$complete[] = array_combine($headers, $row);
}
fclose($handle);
echo json_encode($complete);
I find myself converting csv strings to arrays or objects every few months.
I created a class because I'm lazy and dont like copy/pasting code.
This class will convert a csv string to custom class objects:
Convert csv string to arrays or objects in PHP
$feed="https://gist.githubusercontent.com/devfaysal/9143ca22afcbf252d521f5bf2bdc6194/raw/ec46f6c2017325345e7df2483d8829231049bce8/data.csv";
//Read the csv and return as array
$data = array_map('str_getcsv', file($feed));
//Get the first raw as the key
$keys = array_shift($data);
//Add label to each value
$newArray = array_map(function($values) use ($keys){
return array_combine($keys, $values);
}, $data);
// Print it out as JSON
header('Content-Type: application/json');
echo json_encode($newArray);
Main gist:
https://gist.github.com/devfaysal/9143ca22afcbf252d521f5bf2bdc6194
For those who'd like things spelled out a little more + some room to further parse any row / column without additional loops:
function csv_to_json_byheader($filename){
$json = array();
if (($handle = fopen($filename, "r")) !== FALSE) {
$rownum = 0;
$header = array();
while (($row = fgetcsv($handle, 1024, ",")) !== FALSE) {
if ($rownum === 0) {
for($i=0; $i < count($row); $i++){
// maybe you want to strip special characters or merge duplicate columns here?
$header[$i] = trim($row[$i]);
}
} else {
if (count($row) === count($header)) {
$rowJson = array();
foreach($header as $i=>$head) {
// maybe handle special row/cell parsing here, per column header
$rowJson[$head] = $row[$i];
}
array_push($json, $rowJson);
}
}
$rownum++;
}
fclose($handle);
}
return $json;
}