I have made a simple form with textfields, when i submit a button it wrties all textfield values into a .txt file. Here is an example of the .txt file content:
-----------------------------
How much is 1+1
3
4
5
1
-----------------------------
The 1st and last line ---- is there to just seperate data. The 1st line after the ---- is the question , the before the bottom seperator (1) is the true answer, and all the values between question and true answer are false answers.
What i want to do now is echo out the question , false answers and true answer , seperatly:
echo $quesiton;
print_r ($false_answers); //because it will be an array
echo $true answer;
I think the solution is strpos , but i dont know how to use it the way i want it to. Can i do somethinglike this? :
Select 1st line (question) after the 1st seperator
Select 1st line (true answer) before the 2nd seperator
Select all values inbetween question and true answer
Note that im only showing one example, the .txt file has a lot of these questions seperated with -------.
Are my thoughs correct about using strpos to solve this? Any suggestions?
Edit:
Found some function:
$lines = file_get_contents('quiz.txt');
$start = "-----------------------------";
$end = "-----------------------------";
$pattern = sprintf('/%s(.+?)%s/ims',preg_quote($start, '/'), preg_quote($end, '/'));
if (preg_match($pattern, $lines, $matches)) {
list(, $match) = $matches;
echo $match;
}
I think this might work, not sure yet.
You may try this:
$file = fopen("test.txt","r");
$response = array();
while(! feof($file)) {
$response[] = fgets($file);
}
fclose($file);
This way you will get response array like:
Array(
[0]=>'--------------',
[1]=>'How much is 1+1',
[2]=>'3',
[3]=>'4',
[4]=>'2',
[5]=>'1',
[6]=>'--------------'
)
You could try something like this:
$lines = file_get_contents('quiz.txt');
$newline = "\n"; //May need to be "\r\n".
$delimiter = "-----------------------------". $newline;
$question_blocks = explode($delimiter, $lines);
$questions = array();
foreach ($question_blocks as $qb) {
$items = explode ($newline, $qb);
$q['question'] = array_shift($items); //First item is the question
$q['true_answer'] = array_pop($items); //Last item is the true answer
$q['false_answers'] = $items; //Rest of items are false answers.
$questions[] = $q;
}
print_r($questions);
Related
i am fairly new to PHP and tried several hours to get something going, sadly without a result. I hope you can point me into the right direction.
So what i got is a CSV file containing Articles. They are separated into diff columns and always the same structure, for example :
ArtNo, ArtName, ColorCode, Color, Size
When an article has different color codes in the CSV, the article is simply repeated with the same information except for the color code, see an example:
ABC237;Fingal Edition;48U;Nautical Blue;S - 5XL;
ABC237;Fingal Edition;540;Navy;S - 5XL;
My problem is, i want to display all the articles in a table, include an article image etc.. so far i got that working which is not a problem, but instead of showing the article twice for every different color code i want to create only one line per ArtNo (First CSV Line) but still read the second duplicate line to add the article color to the first one, like :
ABC237; Fingal Edition ;540;Nautical Blue, Navy;S - 5XL;
Is this even possible or am I going into a complete wrong direction here? My code looks like this
<?php
$csv = readCSV('filename.csv');
foreach ($csv as $c) {
$artNo = $c[0]; $artName = $c[1]; $colorCode = $c[2]; $color = $c[3]; $sizes = $c[4]; $catalogue = $c[5]; $GEP = $c[6]; $UVP = $c[7]; $flyerPrice = $c[8]; $artDesc = $c[9]; $size1 = $c[10]; $size2 = $c[11]; $size3 = $c[12]; $size4 = $c[13]; $size5 = $c[14]; $size6 = $c[15]; $size7 = $c[16]; $size8 = $c[17]; $picture = $c[0] . "-" . $c[2] . "-d.jpg";
// Echo HTML Stuff
}
?>
Read CSV Function
<?php
function readCSV($csvFile){
$file_handle = fopen($csvFile, 'r');
while (!feof($file_handle) )
{
$line_of_text[] = fgetcsv($file_handle, 0, ";");
}
fclose($file_handle);
return $line_of_text;
}
?>
I tried to get along with array_unique etc but couldn't find a proper solution.
Read all the data into an array, using the article number as the key....
while (!feof($file_handle) ) {
$values = fgetcsv($file_handle, 0, ";");
$artno = array_shift($values);
if (!isset($data[$artno])) $data[$artno]=array();
$data[$artno][]=$values;
}
And then output it:
foreach ($data as $artno=>$v) {
$first=each($v);
print $artno . "; " . each($first);
foreach ($v as $i) {
$discard=array_shift($i);
print implode(";", $i);
}
print "\n";
}
(code not tested, YMMV)
You need to know exactly how many items belong to each ArtNo group. This means a loop to group, and another loop to display.
When grouping, I steal the ArtNo from the row of data and use it as the grouping key. The remaining data in the row will be an indexed subarray of that group/ArtNo.
I am going to show you some printf() and sprintf() syntax to keep things clean. printf() will display the first parameter's content and using any subsequent values to replace the placeholders in the string. In this case, the 2nd parameter is a conditional expression. On the first iteration of the group, ($i = 0), we want to show the ArtNo as the first cell of the row and declare the number of rows that it should span. sprinf() is just like printf() except it produces a value (silently). Upon any subsequent iterations of the group, $i will be greater than zero and therefore an empty string is passed as the value.
Next, I'm going to use implode() which is beautifully flexible when you don't know exactly how many columns your table will have (or if the number of columns may change during the lifetime of your project).
Tested Code:
$csv = <<<CSV
ABC237;Fingal Edition;48U;Nautical Blue;S - 5XL
ABC236;Fingal Edition;540;Navy;S - 5XL
ABC237;Fingal Edition;49U;Sea Foam;L - XL
ABC237;Fingal Edition;540;Navy;S - 5XL
CSV;
$lines = explode(PHP_EOL, $csv);
foreach ($lines as $line) {
$row = str_getcsv($line, ';');
$grouped[array_shift($row)][] = $row;
}
echo '<table>';
foreach ($grouped as $artNo => $group) {
foreach ($group as $i => $values) {
printf(
'<tr>%s<td>%s</td></tr>',
(!$i ? sprintf('<td rowspan="%s">%s</td>', count($group), $artNo) : ''),
implode('</td><td>', $values)
);
}
}
echo '</table>';
Output:
Lets say I have a text document that cannot be changed in any way and needs to be left as is.
Example of what the text document is likely formatted to be:
1. What is soup commonly paired with?
2.
3.
4. Alcohol
5. Water
6. Bread
7. Vegtables
8.
9.
10.
Note:
The numbers are not included, but they are used to represent the small spaces in between the words that are always there.
There is not always a question mark with the question
Note 2:
The question may be on 2 lines sometimes and may look like this below
0. What is soup
1. commonly paired with?
2.
3.
4. Alcohol
5. Water
6. Bread
7. Vegtables
8.
9.
10.
Other:
So how exactly do I seperate them, for example into an array?
So like $questions[] and $answers[]
The main problem is that I have nothing to link the questions and answers to:
I can't guess the exact line they are on
And the question doesn't always have a question mark
So there is nothing I can really link it to?
Assuming you have already read the text from the document into a variable $text, you can separate the question and answers by splitting on the first blank line in the text.
$qAndAs = preg_split('/\n\s*\n/', $text, 2, PREG_SPLIT_NO_EMPTY);
The split pattern is a line break (\n), zero or more whitespaces (\s*), and another line break.
That should give you an two-element array, where [0] is the question and [1] is the answers.
If it doesn't, then something went wrong.
if (count($qAndAs) !== 2) {
// The text from the document didn't fit the expected pattern.
// Decide how to handle that. Maybe throw an exception.
}
After you have separated them, you can remove any new lines from the question
$question = str_replace(["\r", "\n"], ' ', trim($qAndAs[0]));
and split your answers into another array.
$answers = preg_split('/\s*\n\s*/', $qAndAs[1], -1, PREG_SPLIT_NO_EMPTY);
Both solutions accept multiple questions / answers in a single file.
Solution 1 (similar to the other one in this thread):
$questions = array();
$answers = array();
//Split text into questions and answers blocks (2 line breaks or more from each other)
$text = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
foreach ($text as $key => $value)
{
//0, 2, 4, ... are questions, 1, 3, 5, ... are answers
if ($key % 2)
{
$answers[] = explode("\n", $value);
}
else
{
$questions[] = str_replace("\n", '', $value);
}
}
Solution 2 (ugly line by line reading from a file):
//Open the file
$f = fopen("test.txt","r");
//Initialize arrays of all questions and all answers
$all_questions = array();
$all_answers = array();
$is_question = true;
$last = ''; //contains a previous line
//Iterate over lines
while (true)
{
//Get line
$line = fgets($f);
//Check if end of file
$end = ($line === false);
//Trim current line
$line = trim($line);
if ($line != '')
{
//If the previous line was empty, then reset current question and answers
if ($last == '')
{
$question = array();
$answers = array();
}
//Add line of question or answer
if ($is_question)
{
$question[] = $line;
}
else
{
$answers[] = $line;
}
}
else
{
//If the previous line wasn't empty, or we reached the end of file, then save question / answers, and toggle $is_question
if ($last != '' OR $end)
{
if ($is_question)
{
$all_questions[] = implode(' ', $question); //implode to merge multiline question
$is_question = false;
}
else
{
$all_answers[] = $answers;
$is_question = true;
}
}
}
//Break if end of file
if ($end)
{
break;
}
$last = $line;
}
fclose($f);
I am new to PHP and am trying to create a script that goes through a CSV.
For each row (excluding the headers), checks to see if column 2 and 3 (total rows being 0,1,2,3) when combined, are greater or equal to 1; then display a "1" in column 1. If column 2 and 3 are less than 1, then display "0" in column 1.
An example of the CSV is displayed below:-
sku,is_in_stock,warehouse_3,warehouse_4
AP-STYLUS,1,20,5
RC-3049,0,0,0
NFNC-FLAT-CAP,1,20,20
NFNC-HOOD14-ZIP-S,1,0,5
How can this be done?
You need to replace file.csv with the real filename.
<?php
$str = file_get_contents("file.csv");
//$str = "sku,is_in_stock,warehouse_3,warehouse_4
AP-STYLUS,0,20,5
RC-3049,0,0,0
NFNC-FLAT-CAP,0,20,20
NFNC-HOOD14-ZIP-S,1,0,5";
$arr = explode("\n", $str);
$result = array();
Foreach($arr as $line){
$linearr = explode(",", $line);
if(is_numeric($linearr[2])){
if($linearr[2]+$linearr[3]>=1){
$linearr[1]="1";
$line = implode("," , $linearr);
}else{
$linearr[1]="0";
$line = implode("," , $linearr);
}
}
$result[]=$line;
}
$newstr = implode("\n", $result);
file_put_contents("file.csv", $newstr);
?>
Edit, sorry forgot about the "0" part.
https://3v4l.org/63vmh
I intentionally want to use a text file to do this. So I read a text file and I want to check if a username already exists in that text file or not and I want to either add this username to the text file if he doesn't exists or just add the points to him.
My current code:
<?php
$myfile = fopen("test.txt", "r") or die("Unable to open file!");
$file = fread($myfile,filesize("test.txt"));
//echo $file;
fclose($myfile);
//$username = $_REQUEST['username'];
//$points = $_REQUEST['point'];
$username = 'chinmay'; //chinmay is a username this is unique
$points = 200; //if username chinmay not exitst then Insert first time otherwise if username chimay exist then next onwards this point will update everytime in the text file.
$myfileWrite = fopen("test.txt", "a") or die("Unable to open file!");
$txt = $username."|".$points."\n";
fwrite($myfileWrite, $txt);
fclose($myfileWrite);
?>
test.txt:
chinmay|800
john|200
sanjib|480
debasish|541
This is my complete code. My requirement is:
\n is not working when I am using this text inserted in the same line.
How can I check duplicate username?
If I found username then how can I update user points?
I googled last 2 hours but not getting any solution. I have no idea about this problem.
This should work for you:
First use file() to read your file into an array. Then you can use array_map() to loop through each line and explode() it by | as delimiter. After this you can use array_column() to get the username as key for the points as value. Like this:
Array
(
[chinmay] => 1200
[john] => 200
[sanjib] => 480
[debasish] => 541
[chinmayx] => 200
)
With the array you can simply check if the username already exists or not. If not add it to the array and then add the points to it.
After adding the points to the username you can change your data back in the same format and save it with file_put_contents().
Full code:
<?php
$lines = file("test.txt", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$usernames = array_column(array_map(function($v){
return explode("|", $v);
}, $lines), 1, 0);
$username = "chinmayx";
$points = 200;
if(!isset($usernames[$username]))
$usernames[$username] = 0;
$usernames[$username] += $points;
foreach($usernames as $k => $v)
$data[] = "$k|$v" . PHP_EOL;
file_put_contents("test.txt", $data);
?>
EDIT:
If you have PHP under 5.5 just replace:
$usernames = array_column(array_map(function($v){
return explode("|", $v);
}, $lines), 1, 0);
with this:
$lines = array_map(function($v){
return explode("|", $v);
}, $lines);
$usernames = array_combine(
array_map(function($v){
return $v[0];
}, $lines),
array_map(function($v){
return $v[1];
}, $lines)
);
Also if you want to get the TOP 10 users, just rsort() your array and then take an array_slice() of the first 10 elements, e.g.
rsort($usernames);
$topUsers = array_slice($usernames, 0, 10);
print_r($topUsers);
To get the \n working use the PHP_EOL as in another answer
$txt = $username."|".$points.PHP_EOL;
To update the user found in the text file go through following link
how to replace a particular line in a text file using php?
you should use PHP_EOL instead of "\n" which also depends on your OS
$txt = $username."|".$points.PHP_EOL;
for checking userName, just use:
//this works because $file is String because of fread()
if (strpos($file,$username) !== false) {
echo 'user exists';
}
for replacing you'll need regex or use strpos position (which returns position of name in string) and advance the pointer by count($username)+1 and search from there for newline, all this string between that, replace with new points
Try to use preg_match:
$file = fopen("score.txt", "r");
while (!feof($file)) {
preg_match("/^$username|(.*?)$/", $file, $array);
var_dump($array);
}
but I think it's better to use MySQL :)
I'm trying to read data from a.csv file to ouput it on a webpage as text.
It's the first time I'm doing this and I've run into a nasty little problem.
My .csv file(which gets openened by Excel by default), has multiple rows and I read the entire thing as one long string.
like this:
$contents = file_get_contents("files/data.csv");
In this example file I made, there are 2 lines.
Paul Blueberryroad
85 us Flashlight,Bag November 20,
2008, 4:39 pm
Hellen Blueberryroad
85 us lens13mm,Flashlight,Bag,ExtraBatteries November
20, 2008, 16:41:32
But the string read by PHP is this:
Paul;Blueberryroad 85;us;Flashlight,Bag;November 20, 2008, 4:39 pmHellen;Blueberryroad 85;us;lens13mm,Flashlight,Bag,ExtraBatteries;November 20, 2008, 16:41:32
I'm splitting this with:
list($name[], $street[], $country[], $accessories[], $orderdate[]) = split(";",$contents);
What I want is for $name[] to contain "Paul" and "Hellen" as its contents. And the other arrays to receive the values of their respective columns.
Instead I get only Paul and the content of $orderdate[] is
November 20, 2008, 4:39 pmHellen
So all the rows are concatenated. Can someone show me how i can achieve what I need?
EDIT: solution found, just one werid thing remaining:
I've solved it now by using this piece of code:
$fo = fopen("files/users.csv", "rb+");
while(!feof($fo)) {
$contents[] = fgetcsv($fo,0,';');
}
fclose($fo);
For some reason, allthough my CSV file only has 2 rows, it returns 2 arrays and 1 boolean. The first 2 are my data arrays and the boolean is 0.
You are better off using fgetcsv() which is aware of CSV file structure and has designated options for handling CSV files. Alternatively, you can use str_getcsv() on the contents of the file instead.
The file() function reads a file in an array, every line is an entry of the array.
So you can do something like:
$rows = array();
$name = array();
$street = array();
$country = array();
$rows = file("file.csv");
foreach($rows as $r) {
$data = explode(";", $r);
$name[] = $data[0];
$street[] = $data[1];
$country[] = $data[2];
}
I've solved it now by using this piece of code:
$fo = fopen("files/users.csv", "rb+");
while(!feof($fo)) {
$contents[] = fgetcsv($fo,0,';');
}
fclose($fo);
For some reason, allthough my CSV file only has 2 rows, it returns 2 arrays and 1 boolean. The first 2 are my data arrays and the boolean is 0.
The remark about fgetcsv is correct.
I will still answer your question, for educational purpose. First thing, I don't understand the difference between your data (with comas) and the "string read by PHP" (it substitutes some spaces with semi-colon, but not all?).
PS.: I looked at the source code of your message, it looks like an odd mix of TSV (tabs) and CSV (coma).
Beside, if you want to go this way, you need to split first the file in lines, then the lines in fields.
The best way is of course fgetcsv() as pointed out.
$f = fopen ('test.csv', 'r');
while (false !== $data = fgetcsv($f, 0, ';'))
$arr[] = $data;
fclose($f);
But if you have the contents in a variable and want to split it, and str_getcsv is unavailable you can use this:
function str_split_csv($text, $seperator = ';') {
$regex = '#' . preg_quote($seperator) . '|\v#';
preg_match('|^.*$|m', $text, $firstline);
$chunks = substr_count($firstline[0], $seperator) + 1;
$split = array_chunk(preg_split($regex, $text), $chunks);
$c = count($split) - 1;
if (isset($split[$c]) && ((count($split[$c]) < $chunks) || (($chunks == 1) && ($split[$c][0] == ''))))
unset($split[$c]);
return $split;
}