I am reading a txt file on the following way:
$handle = fopen($captionTextFile, "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
echo ($line);
}
fclose($handle);
}
// Output
IMAG0986.jpg|Title something 1 here|<b>Description</b><br />You can use HTML as you can see!
IMAG0988.jpg|Title something 2 here|<b>Description</b><br />You can use HTML as you can see!
etc...
Now I want to store only the values between the first | by line in a php array. Example of what I intend to have:
$json = '{"IMAG0986.jpg": "Title something 1 here",
"IMAG0988.jpg": "Title something 2 here"}';
In order to access this array later in this way:
$obj = json_decode($json);
print $obj->{'IMAG0986.jpg'}; // print: "Title something 1 here"
The problem that I'm having is how do I pass the values from the lines to the array? any help please?
Use file() to read the file lines to an array, then use explode() with | delimiter and add the 1st part as key and 2nd as value to an array, finally use json_encode().
Something like:
<?php
$captionTextFile = "test.pipe";
$arrayFinal = array();
$lines = file($captionTextFile);
foreach($lines as $line) {
$array = explode("|", $line);
$arrayFinal[$array[0]] = $array[1];
}
print_r(json_encode($arrayFinal));
//{"IMAG0986.jpg":"Title something 1 here","IMAG0988.jpg":"Title something 2 here"}
//If you don't need json, just access the array by key:
echo $arrayFinal['IMAG0986.jpg'];
//Title something 1 here
You can explode() the lines into keys and values in an object to achieve that desired JSON result.
$data = new stdClass();
$handle = fopen($captionTextFile, "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
$row = explode('|', $line);
$data->{$row[0]} = row[1];
}
fclose($handle);
}
json_encode($data);
I am trying to convert CSV file to JSON using PHP.
Here is my code
<?php
date_default_timezone_set('UTC');
$today = date("n_j"); // Today is 1/23/2015 -> $today = 1_23
$file_name = $today.'.CSV'; // My file name is 1_23.csv
$file_path = 'C:\\Users\\bheng\\Desktop\\qb\\'.$file_name;
$file_handle = fopen($file_path, "r");
$result = array();
if ($file_handle !== FALSE) {
$column_headers = fgetcsv($file_handle);
foreach($column_headers as $header) {
$result[$header] = array();
}
while (($data = fgetcsv($file_handle)) !== FALSE) {
$i = 0;
foreach($result as &$column) {
$column[] = $data[$i++];
}
}
fclose($file_handle);
}
// print_r($result); // I see all data(s) except the header
$json = json_encode($result);
echo $json;
?>
print_r($result); // I see all data(s)
Then I json_encode($result); and tried to display it, but nothing is displaying on the screen at all. All I see is the blank screen, and 0 error message.
Am I doing anything wrong ? Can someone help me ?
Added Result of print_r($result);
Array (
[Inventory] => Array (
[0] => bs-0468R(20ug)
[1] => bs-1338R(1ml)
[2] => bs-1557G(no bsa)
[3] => bs-3295R(no BSA)
[4] => bs-0730R-Cy5"
[5] => bs-3889R-PE-Cy7"
[6] => 11033R
[7] => 1554R-A647
[8] => 4667
[9] => ABIN731018
[10] => Anti-DBNL protein
.... more ....
Try like this:
$file="1_23.csv";
$csv= file_get_contents($file);
$array = array_map("str_getcsv", explode("\n", $csv));
$json = json_encode($array);
print_r($json);
data.csv
Game,Skill
Treasure Hunter,pilipala
Rocket Launcher,bibobibo
Rocket Engine,hehehohoho
To convert with column name, this is how I do it.
csv2json.php
<?php
if (($handle = fopen("data.csv", "r")) !== FALSE) {
$csvs = [];
while(! feof($handle)) {
$csvs[] = fgetcsv($handle);
}
$datas = [];
$column_names = [];
foreach ($csvs[0] as $single_csv) {
$column_names[] = $single_csv;
}
foreach ($csvs as $key => $csv) {
if ($key === 0) {
continue;
}
foreach ($column_names as $column_key => $column_name) {
$datas[$key-1][$column_name] = $csv[$column_key];
}
}
$json = json_encode($datas);
fclose($handle);
print_r($json);
}
The output result
[
{
"Game": "Treasure Hunter",
"Skill": "pilipala"
},
{
"Game": "Rocket Launcher",
"Skill": "bibobibo"
},
{
"Game": "Rocket Engine",
"Skill": "hehehohoho"
}
]
You can try this way too.
<?php
function csvtojson($file,$delimiter)
{
if (($handle = fopen($file, "r")) === false)
{
die("can't open the file.");
}
$csv_headers = fgetcsv($handle, 4000, $delimiter);
$csv_json = array();
while ($row = fgetcsv($handle, 4000, $delimiter))
{
$csv_json[] = array_combine($csv_headers, $row);
}
fclose($handle);
return json_encode($csv_json);
}
$jsonresult = csvtojson("./doc.csv", ",");
echo $jsonresult;
I ran into a similar problem, I ended up using this to recursively convert the data to UTF-8 on an array before encoding to JSON.
function utf8_converter($array)
{
array_walk_recursive($array, function(&$item, $key){
if(!mb_detect_encoding($item, 'utf-8', true)){
$item = utf8_encode($item);
}
});
return $array;
}
From:
http://nazcalabs.com/blog/convert-php-array-to-utf8-recursively/
This issue is pretty old by now, but hoping this helps someone, as it seemed like the simplest example I found, and I know this is a pretty common thing devs might need to do as a beginner, and lots of answers gloss over the magic.
$file = storage_path('app/public/waitlist_users_test.csv'); //--> laravel helper, but you can use any path here
function csv_to_json($file)
{
// file() loads each row as an array value, then array map uses the 'str_getcsv' callback to
$csv = array_map('str_getcsv', file($file));
// array_walk - "walks" through each item of the array and applies the call back function. the & in "&row" means that alterations to $row actually change the original $csv array, rather than treating it as immutable (*sort of immutable...)
array_walk($csv, function(&$row) use ($csv) {
// array_combine takes the header row ($csv[0]) and uses it as array keys for each column in the row
$row = array_combine($csv[0], $row);
});
array_shift($csv); # removes now very redundant column header --> contains {'col_1':'col_1', 'col_2':'col_2'...}
$json = json_encode($csv);
return $json;
}
There's a lot of magic going on with these functions that accept callback functions, that didn't seem to be explained thoroughly above. I'm self taught and have been programming for years, and find that it's often just glossed over without detailing how callbacks work, so I'll dive in just a little bit for the array_map('str_getcsv', file($file)) function - if you pass a function you've written, or inbuilt php function name as a string, it will take the value of whatever (in this case - array) element is being evaluated by the calling function (in this case array_map), and pass that to the callback function without the need to explicitly pass in a variable - super helpful once you get the hang of it, but I find it's not explained thoroughly very often which leaves beginners to not understand why it works, just that it works.
I've linked most of these above, but here's a little more information:
str-getcsv do? Array Walk Array Map Callables/Callbacks
as #MoonCactus noted, the file() function only loads 1 row at a time which helps save on memory usage for large .csv files.
Also, some other posts reference using explode - why not use explode() instead of str_getcsv() to parse rows? Because explode() would not treat possible enclosured parts of string or escaped characters correctly.
Hope somebody finds this helpful!
If you are converting a dynamic CSV file, you can pass the URL through a parameter (url=http://example.com/some.csv) and it will show you the most up-to-date version:
<?php
// Lets the browser and tools such as Postman know it's JSON
header( "Content-Type: application/json" );
// Get CSV source through the 'url' parameter
if ( isset( $_GET['url'] ) ) {
$csv = explode( "\n", file_get_contents( $_GET['url'] ) );
$index = str_getcsv( array_shift( $csv ) );
$json = array_map(
function ( $e ) use ( $index ) {
return array_combine( $index, str_getcsv( $e ) );
}, $csv
);
}
else {
$json = "Please set the path to your CSV by using the '?url=' query string.";
}
// Output JSON
echo json_encode( $json );
Alternate solution that uses similar method as #Whirlwind's solution but returns a more standard JSON result (with named fields for each object/record):
// takes a string of CSV data and returns a JSON representing an array of objects (one object per row)
function convert_csv_to_json($csv_data){
$flat_array = array_map("str_getcsv", explode("\n", $csv_data));
// take the first array item to use for the final object's property labels
$columns = $flat_array[0];
for ($i=1; $i<count($flat_array)-1; $i++){
foreach ($columns as $column_index => $column){
$obj[$i]->$column = $flat_array[$i][$column_index];
}
}
$json = json_encode($obj);
return $json; // or just return $obj if that's a more useful return value
}
The accepted answer uses file_get_contents() to read the entire file as a string in memory, and then explode() it to make it an array.
But it can be made faster, smaller in memory, and more useful:
function ReadCsv($fn)
{
$lines= file($fn); // read file directly as an array of lines
array_pop($lines); // you can remove the last empty line (if required)
$json= json_encode(array_map("str_getcsv", $lines), JSON_NUMERIC_CHECK);
print_r($json);
}
Nb: I used JSON_NUMERIC_CHECK here to avoid numbers being double quoted into strings. It also reduces the output size and it usually helps javascript on the other side (e.g. to compute or plot the data). Beware of phone numbers though!
I liked #ian-d-miller's solution for converting the data into a key / value style format, but I kept running into issues with his code.
Here's what worked for me:
function convert_CSV_to_JSON($csv_data){
// convert csv data to an array
$data = array_map("str_getcsv", explode("\n", $csv_data));
// use the first row as column headers
$columns = $data[0];
// create array to hold our converted data
$json = [];
// iterate through each row in the data
foreach ($data as $row_index => $row_data) {
// skip the first row, since it's the headers
if($row_index === 0) continue;
// make sure we establish each new row as an array
$json[$row_index] = [];
// iterate through each column in the row
foreach ($row_data as $column_index => $column_value) {
// get the key for each entry
$label = $columns[$column_index];
// add this column's value to this row's index / column's key
$json[$row_index][$label] = $column_value;
}
}
// bam
return $json;
}
Usage:
// as is
$json = convert_CSV_to_JSON($csv);
// encoded
$json = json_encode($json);
Something that i've made for myself and may be useful for others :)
This will convert CSV into JSON array with objects (key => value pair).
function csv2json($a, $e = true) {
$b = ["\r\n","\r","\n",];
foreach ($b as $c => $d) {
$a = explode($d, $a);
$a = isset($b[$c + 1]) ? implode($b[$c + 1], $a) : implode(PHP_EOL, $a);
}
// Convert to CSV
$a = array_map("str_getcsv", explode(PHP_EOL, $a));
// Get the first part of the array as the keys
$a = [
"keys" => array_shift($a),
"rows" => $a,
"row" => null,
];
// Define JSON
$b = [];
foreach ($a["rows"] as $a["row"]) {
$a["row"] = [ "csv" => $a["row"], "json" => (object)[], ];
for ($c = 0; $c < count($a["row"]["csv"]); $c++) {
$a["row"]["csv"][$c] = [#json_decode($a["row"]["csv"][$c]),$a["row"]["csv"][$c]];
// Switch from string to booleans, numbers and others
$a["row"]["csv"][$c] = isset($a["row"]["csv"][$c][0]) ? $a["row"]["csv"][$c][0] : $a["row"]["csv"][$c][1];
// Push it back
$a["row"]["json"]->{$a["keys"][$c]} = $a["row"]["csv"][$c];
}
$a["row"] = $a["row"]["json"];
$b[] = $a["row"];
unset($a["row"]);
}
// $e will be "return"
$e = $e ? json_encode($b) : $b;
// Unset useless variables
unset($a, $b, $c, $d);
return $e;
}
How to use?
If you want to return the JSON as a string, Leave it as default.
If you want to return the JSON as an object / array, set the second parameter to false.
Examples:
$csv = "name,age,gender
John Doe,35,male
Jane Doe,32,female";
echo csv2json($csv, true); // Or without the second parameter, just csv2json($csv)
The example above (^) will return a JSON stringified, Like this:
[{"name":"John Doe","age":35,"gender":"male"},{"name":"Jane Doe","age":32,"gender":"female"}]
and the example below:
var_dump(csv2json($csv, false));
will return a JSON array with these objects:
array(2) {
[0]=>
object(stdClass)#1 (3) {
["name"]=>
string(8) "John Doe"
["age"]=>
int(35)
["gender"]=>
string(4) "male"
}
[1]=>
object(stdClass)#2 (3) {
["name"]=>
string(8) "Jane Doe"
["age"]=>
int(32)
["gender"]=>
string(6) "female"
}
}
public function CsvToJson($fileContent){
//Convert CSV To Json and Return
$all_rows = array();
$newhead =array();
//Extract csv data to array on \n
$array = explode("\n",$fileContent);
//Extract csv header to array on 0 Index
$header = explode(",",$array[0]);
//Remove Header Row From Main Data Array
array_shift($array);
//Extract All Arrays To Saperate Orders
foreach($array as $arr){
$sliced = explode(",",$arr);
array_push($all_rows,$sliced);
}
//Extract All Orders Element To Saperate Array Item
foreach($all_rows as $row){
$sliced = explode(",",$arr);
array_push($all_rows,$sliced);
}
//Remove \r From Header Elements
foreach($header as $key=>$value){
$sliced = str_replace ("\r", "", $value);
array_push($newhead,$sliced);
}
//COMBINE Header as KEY And Row Element As Value
$arrrr = array();
foreach($all_rows as $row) {
//Remove Last Element of ROW if it is \r (Break given in css file for next row)
$count= count($row);
if ($row[$count-1] == "\r") {
array_splice($row, count($row) - 1, 1);
}
//CHECK IF HADER COUNT == ROW COUNT
if (count($header) == count($row)) {
array_push($arrrr,array_combine($newhead,$row));
}
}
//CONVERT ARRAY TO JSON
$json = json_encode($arrrr);
//Remove backslasesh from json key and and value to remove \r
$clean = stripslashes($json);
//CONVERT ARRAY TO JSON AGAIN FOR EXPORT
$jsonagain = json_encode($clean);
return $jsonagain;
}
I want to record downloads in a text file
Someone comes to my site and downloads something, it will add a new row to the text file if it hasn't already or increment the current one.
I have tried
$filename = 'a.txt';
$lines = file($filename);
$linea = array();
foreach ($lines as $line)
{
$linea[] = explode("|",$line);
}
$linea[0][1] ++;
$a = $linea[0][0] . "|" . $linea[0][1];
file_put_contents($filename, $a);
but it always increments it by more than 1
The text file format is
name|download_count
You're doing your incrementing outside of the for loop, and only accessing the [0]th element so nothing is changing anywhere else.
This should probably look something like:
$filename = 'a.txt';
$lines = file($filename);
// $k = key, $v = value
foreach ($lines as $k=>$v) {
$exploded = explode("|", $v);
// Does this match the site name you're trying to increment?
if ($exploded[0] == "some_name_up_to_you") {
$exploded[1]++;
// To make changes to the source array,
// it must be referenced using the key.
// (If you just change $v, the source won't be updated.)
$lines[$k] = implode("|", $exploded);
}
}
// Write.
file_put_contents($filename, $lines);
You should probably be using a database for this, though. Check out PDO and MYSQL and you'll be on your way to awesomeness.
EDIT
To do what you mentioned in your comments, you can set a boolean flag, and trigger it as you walk through the array. This may warrant a break, too, if you're only looking for one thing:
...
$found = false;
foreach ($lines as $k=>$v) {
$exploded = explode("|", $v);
if ($exploded[0] == "some_name_up_to_you") {
$found = true;
$exploded[1]++;
$lines[$k] = implode("|", $exploded);
break; // ???
}
}
if (!$found) {
$lines[] = "THE_NEW_SITE|1";
}
...
one hand you are using a foreach loop, another hand you are write only the first line into your file after storing it in $a... it's making me confuse what do you have in your .txt file...
Try this below code... hope it will solve your problem...
$filename = 'a.txt';
// get file contents and split it...
$data = explode('|',file_get_contents($filename));
// increment the counting number...
$data[1]++;
// join the contents...
$data = implode('|',$data);
file_put_contents($filename, $data);
Instead of creating your own structure inside a text file, why not just use PHP arrays to keep track? You should also apply proper locking to prevent race conditions:
function recordDownload($download, $counter = 'default')
{
// open lock file and acquire exclusive lock
if (false === ($f = fopen("$counter.lock", "c"))) {
return;
}
flock($f, LOCK_EX);
// read counter data
if (file_exists("$counter.stats")) {
$stats = include "$counter.stats";
} else {
$stats = array();
}
if (isset($stats[$download])) {
$stats[$download]++;
} else {
$stats[$download] = 1;
}
// write back counter data
file_put_contents('counter.txt', '<?php return ' . var_export($stats, true) . '?>');
// release exclusive lock
fclose($f);
}
recordDownload('product1'); // will save in default.stats
recordDownload('product2', 'special'); // will save in special.stats
personally i suggest using a json blob as the content of the text file. then you can read the file into php, decode it (json_decode), manipulate the data, then resave it.
I have a simple ini file:
[section_one]
test = abc
[section_two]
yada = blah
#and_so=on
I wrote a parser function to update it b/c my comment char is '#' instead of ';' -- so parse_ini_file() complains. But here's my quick & dirty solution:
<?php
function edit_ini_file ($fName, $fKey, $fVal) {
print"<h4>Search: $fKey = $fVal </h4>";
// declarations
$_comntChar='#';
$_headrChar='[';
$keyMatch=FALSE;
$iniArray = array(); // new array in memory
$dataOut = ''; // datastream for output file
// temp cursor vars for looping & reporting
$verbose = 1;
$curSec = ''; // current section
$curKey = ''; // current key
$curVal = ''; // current value
$curLine=-1; // current line Number
if (isset($fName)) {
if (!is_file($fName)) return FALSE;
$lines = file($fName);
//read file as array of lines
foreach ($lines as $line) {
$curLine+=1;
if ($verbose) print '<br/>['.$curLine.'][IN:] '.$line;
//parse for k/v pairs, comments & section headings
if ( (strpos($line,$_headrChar)==1) // assume heading
|| (strpos($line,$_comntChar)==1) // assume comment
|| (!strpos($line,'=')) // also skip invalid k/v pairs
){
array_push($iniArray, $lines[$curLine] ); //stuff the entire line into array.
if ($verbose) print " - no k/v";
} else { // assume valid k/v pair
//split k/v pairs & parse for match
$pair = explode('=', $line);
$curKey = trim($pair[0]);
$curVal = trim($pair[1]);
if ($verbose) print "[KV]: k=$curKey:v=$curVal";
if (trim($curKey) === trim($fkey)) { // <=== THE BUGGER: never returns true:
$keyMatch=TRUE;
print ("MATCH: Replacing value in for key=$curKey in Section $curSec at line $curLine<br/>");
array_push ($iniArray, array($curKey => $fVal ));
} else {
array_push ($iniArray, array($curKey => $curVal ));
} //end-matcher
} //end-parser
} //end foreach
if (!$keyMatch) { //append new data to end
print "<br/>Key not Found. Appending! <br/>";
array_push ($iniArray, array($fKey => $fVal) );
}
//reformat nested array as one long string for a single bulk-write to disk.
foreach($iniArray as $curSect => $val) {
if (is_array($val)) {
foreach($val as $curKey => $curVal)
$dataOut .= "$curKey = $curVal\n";
} else { $dataOut .= "$val"; }
}
print "dataout:<pre>" .$dataOut. "</pre>";
//put file & pass return val
return (file_put_contents($filename, $dataOut)) ? TRUE : FALSE;
}//if isset
}//end-func
Basically I'm just exploding a text file line-by-line stuffing a new array and dumping it back to the disk
MY BUG: for some reason my comparison trying strcmp() or "==" or "===" never seems to work...
if (trim($curKey) === trim($fkey)) { doSomething.. }
That little BUGGER is driving me nuts b/c I know it's gotta be something stupid.
ANy point in the right direction would be appreciated...
Is it $fKey or $fkey?
Make a decision!
;)
Let say i want to read a text file using php.
Now my text file contain
User=Test
Age=18
Gender=F
User=Test2
Age=34
Gender=M
and following like that.
Now let say i want to use php to read the text file and find only value of User= and display it.
What is the easiest way to accomplish this?
Thank you.
This may be more than you're looking for, but if you're looking to parse a text file
and you're not tied to a specificformat you should use one that php has inbuilt support for. To me the two most obvious options are XML and JSON. IMHO JSON is probably easiest.
In your example the data file might look like this
[
{
'User':'Test',
'Age':18,
'Gender':'F'
},
{
'User':'Test2',
'Age':34,
'Gender':'M'
}
]
The php to read from it would be
contents = file_get_contents($filename);
$contents = utf8_encode($contents);
$m = json_decode($contents);
Now you can work on $m as you would any array
foreach( $m as $user )
{
print $user->User . "\n";
}
$filename = "users.txt";
$user_file_array = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
//Now you have an array of each line of the file.
foreach($user_file_array as $user_info) {
if(strpos($user_info, "User=") !== false) {
$users[] = str_replace("User=", "", $user_info);
}
}
The above assumes that each bit of info is on a new line, that User= is case-sensitive, and that you are okay with looping through whole file. You will get an array returned of just the user names on the right-side of the User=.
If you want that to be echoed out in a column, either change the bit where the $users array gets built, or add this to the end:
echo implode("\n" $users);
Unless you're looking for a specific value, you're basically going to have to read the whole file in to memory. You could read it line-by-line and output any line that started with "User", like this:
$fp = fopen("test_input.txt","r");
while(! feof($fp)) {
$line = fgets($fp);
if (substr($line,0,5) == "User=") echo substr($line,5);
}
fclose($fp);
If you wanted the information in a more useful form, you could break it up into an array of users. Assuming that each "section" of your file is separated by a double newline, you could do this:
$out = array();
$contents = file_get_contents('test_input.txt');
$blocks = explode("\n\n",$contents);
foreach($blocks as $b)
{
$user = array();
$lines = explode("\n",$b);
foreach($lines as $line) {
list($key,$value) = explode("=",$line,2);
$user[$key] = $value;
}
$out[] = $user;
}
//now have an array of user info
foreach($out as $i) echo $i['User'];
Obviously this makes assumptions about your data (such as all lines separated by "\n" characters), but you get the idea.
You could try fgets() to get a line of the file and substring the beginning to test if it starts with the proper text. There may be easier ways.
<?php
$lines = array();
$file = fopen("sample.txt", "r") or exit("Unable to open file!");
//Output a line of the file until the end is reached
$i = 0;
while(!feof($file))
{
$i++;
$lines[$i] = fgets($file). "<br />";
}
fclose($file);
$matches = preg_grep("/^User=(.*)/", $lines);
print_r($matches);
?>
Taken from http://php.net/manual/en/function.preg-grep.php, http://www.phpfreaks.com/forums/index.php?topic=213127.0
If you're married to/stuck with the format that you described, then you can try out my code below. It will give you a nice array that you can work with easily. Otherwise, I suggest you take Michael Anderson's advice and switch over to JSON as it will save you time and normalize things a bit.
$rawData = file_get_contents("data.txt");
$users = array();
$tmpUser = array();
foreach ( file("data.txt", FILE_IGNORE_NEW_LINES) as $line ) {
// Blank line denotes the end of a record
if ( empty($line) ) {
$users[] = $tmpUser;
$tmpUser = array();
continue;
}
list($key, $value) = explode("=", $line, 2);
$tmpUser[ strtolower(trim($key)) ] = trim($value);
}
// Add last record
if ( !empty($tmpUser) ) {
$users[] = $tmpUser;
}
print_r($users);
Result
Array
(
[0] => Array
(
[user] => Test
[age] => 18
[gender] => F
)
[1] => Array
(
[user] => Test2
[age] => 34
[gender] => M
)
)
I realize that you asked specifically to be able to get just the user name; however, this is probably more beneficial in the term of whatever you are trying to accomplish.
chk this code
<?php
$file = "test.txt";
$userArr=array();
$f = fopen($file, "r");
while ( $line = fgets($f) )
{
$lineArr = explode('=',$line);
if($lineArr[0]=='User')
{
echo "User Name: ".$lineArr[1];
echo "<br/>";
$userArr[] = $lineArr[1];
}
}
print_r($userArr);
?>
For more info chk this here