I am trying to get my head around the way PHP sessions work. I am simply trying a hangman game where the first player inputs a secret word, a second player then starts to guess one letter at a time.
Let's says that the secret word is cat, player two tries, c then a then s. I would like the final output to be c a _.
<?php
session_start();
global $word;
global $guess;
global $hangman;
if (isset($_POST['player1'], $_POST['word'])) {
$_SESSION['word'] = $_POST['word'];
$word = $_SESSION['word'];
}
if (isset($_POST['player2'], $_POST['guess'])) {
$_SESSION['guess'] = $_POST['guess'];
$guess = $_SESSION['guess'];
}
$counter = 0;
$word = strtolower($_SESSION['word']);
$guess = strtolower($_SESSION['guess']);
echo $word . "<br>";
$found = [];
$counter = 0;
for ($i = 0; $i < strlen($word); $i++) {
if ($counter < strlen($word)) {
if (strpos($word[$i], $guess) !== false) {
$found[] = $guess;
$counter++;
} else {
$found[] = " _ ";
}
}
}
print_r($found);
Instead of printing out all the contents the found array, I am only getting one single letter to print every time. However, I would like to see the full concatenated string as I've mentioned above.
Here is what the output looks like:
How to continuously push user input data into $_SESSION array and then retrieve it?
An easy way to do that is by binding a variable with an element in the $_SESSION array.
This is a useful trick that you won't find in the manual.
A simple example:
$foo =& $_SESSION['foo'];
That assignment will bind $foo and $_SESSION['foo'] to the same value,
so every update to $foo is also an update to $_SESSION['foo'].
Here is an example usage in the style of your hangman game:
<?php
session_start();
$word =& $_SESSION['word']; //bind $word with $_SESSION['word']
$found =& $_SESSION['found']; //bind $found with $_SESSION['found']
if (isset($_REQUEST['word'])) {
$word = str_split($_REQUEST['word']);
$found = array_fill(0, count($word), '_');
}
if (isset($_REQUEST['guess'], $word, $found)) {
$guess = array_fill(0, count($word), $_REQUEST['guess']);
$found = array_replace($found, array_intersect($word, $guess));
}
echo join(' ', $found);
With the binding, the values of $word and $found will be saved as a part of the session data,
without the need to do $_SESSION['word'] = $word; and $_SESSION['found'] = $found; anywhere in the script.
Note that I use $_REQUEST instead of $_POST to make it easier to test with a browser.
Modify as desired.
Make the $found as a string variable.Instead of pushing in $found[] ,concatenate $guess Like $found .= $guess;
You should save what was already found between requests, since now you are just searching the $_SESSION['word'] for the char in the last request.
if ( isset($_POST['player1']) && !empty($_POST['word']) ) {
$_SESSION['word'] = str_split( $_POST['word'] );
// ceate empty array for storing the already found chars
$_SESSION['found'] = str_split( str_repeat( " ", strlen($_POST['word']) ) );
}
if ( isset($_POST['player2']) && !empty($_POST['guess']) ) {
array_walk( $_SESSION['word'], function( $v, $k ) {
if ( $v == $_POST['guess'] )
$_SESSION['found'][$k] = $v;
});
}
if ( $_SESSION['word'] == $_SESSION['found'] )
echo 'Game Over';
print_r( $_SESSION['found'] );
You are overwriting your $_SESSION['guess'] with:
$_SESSION['guess'] = $_POST['guess'];
on every submission.
I would recommend that you store your posted guesses as a subarray of letters like:
$_SESSION['guesses'][] = $_POST['guess'];
Then you will never overwrite earlier guesses.
This will mean you will have a session array with this type of structure:
$_SESSION=[
'player1' => 'me',
'word' => 'cat',
'player2' => 'myself',
'guesses' => ['a','c']
];
From here, you can call str_split() on $_SESSION['word'] and check for found/remaining letters using $_SESSION['guesses'] and array comparison functions.
Here are some untested portions of code that may help you along...
session_start();
if (!isset($_SESSION['player1'], $_SESSION['word'])) { // no stored player1 or word
if (!isset($_POST['player1'], $_POST['word'])) { // no posted player1 or word
// show form with player1 and word fields
} else {
$_SESSION=['player1'=>$_POST['player1'],'word'=>strtolower($_POST['word'])]; // store player1 and word
}
} elseif (!isset($_SESSION['player2'], $_SESSION['guesses'])){ // no stored player2 or guesses
if (!isset($_POST['player2'], $_POST['guess'])) { // no posted player2 or guess
// show form with player2 and first guess
} else {
$_SESSION['player2'] = $_POST['player1']; // store player2
$_SESSION['guesses'] = [strtolower($_POST['guess'])]; // store guessed character as first element of subarray
}
} elseif (isset($_POST['guess'])) {
$_SESSION['guesses'][] = strtolower($_POST['guess']); // store guessed character
}
And further down script here are some pieces...
$secret_letters=array_unique(str_split($_SESSION['word'])); // unique secret word letters
$found_letters=array_intersect($secret_letters,$_SESSION['guesses']); // unique found letters
if($secret_letters===$found_letters){
// player2 guessed all of the secret letters, set off fireworks
}else{
// some useful bits of code...
$not_yet_found=array_diff($secret_letters,$_SESSION['guesses']);
$underscored=str_replace($not_yet_found,'_',$_SESSION['word']); // e.g. 'ca_'
$space_out=implode(' ',str_split($underscored)); // e.g. 'c a _'
$wrong_letters=array_diff($_SESSION['guesses'],$secret_letters); // letters guessed but not part of secret word
// when count($wrong_letters) reaches your designated limit, then the guesser loses
$avaliable_letters=array_diff(range('a','z'),$_SESSION['guesses']);
$select="<select name=\"guess\"><option>".implode('</option><option>',$available_letters)."</option></select>";
}
I should also note, there are many ways to tackle this project. You should have a look at count_chars(), it has multiple modes which you should research and consider.
There will be regex methods that may be helpful, but I won't open up that can for you.
I see your problem now. you didn't save or hold the previous guess because your found[] array variable is always empty.
try to save the found result in a session
and change this following line of code:
for ($i = 0; $i < strlen($word); $i++) {
if ($counter < strlen($word)) {
if (strpos($word[$i], $guess) !== false) {
$found[] = $guess;
$counter++;
} else {
$found[] = " _ ";
}
}
}
TO:
$counterWord = strlen($word);
for ($i = 0; $i < $counterWord ; $i++) {
if (strpos($word[$i], $guess) !== false) {
$found[$i] = $guess; // $i indicates what index should be changed
} else {
if(!isset($found[$i])){
$found[$i] = "_";
}
}
$_SESSION['found'] = $found;
and add this line of code under the declaring of your $found array variable:
$found = [];
if(isset($_SESSION['found'])){ //checker if the variable is set and not empty
$found = $_SESSION['found']; // getting the value of found and store it in found variable
}
I have a text file with a lot of inserts that looks like this:
INSERT INTO yyy VALUES ('1','123123','da,sdadwa','6.7','24f,5','f5,5','dasdad,fsdfsdfsfsasada dasdasd','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','dasdasd','q231e','','0','','g','1','123123','dasdadwa','6.7','24f,5','f5,5','dasdad,fsdfsdfsfsasada dasdasd','','','q231e','','0','','a','1','123123','dasdadwa','655.755','24f,5','f5,5','dasdad,fsdfsdfsfsasada dasdasd','','','q231e','','','','a');
INSERT INTO yyy VALUES ('2','123123','dasdadwa','6.8','24f,6','f5,5','dasdad,fsdfsdfsfsasada dasdasd','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','dasdasd','q231e','','0','','g','2','123123','dasdadwa','6.8','24f,6','f5,5','dasdad,fsdfsdfsfsasada dasdasd','','','q231e','','0','','a','2','123123','dasdadwa','6.8','24f,6','f5,5','dasdad,fsdfsdfsfsasada dasdasd','','','q231e','','','','a');
INSERT INTO yyy VALUES ('3','123123','dasdadwa','6.9','24f,7','f5,5','dasdad,fsdfsdfsfsasada dasdasd','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','dasdasd','q231e','','0','','g','3','123123','dasdadwa','6.9','24f,7','f5,5','dasdad,fsdfsdfsfsasada dasdasd','','','q231e','','0','','a','3','123123','dasdadwa','6.9','24f,7','f5,5','dasdad,fsdfsdfsfsasada dasdasd','','','q231e','','','','a');
INSERT INTO yyy VALUES ('4','123123','dasdadwa','6.10','24f,8','f5,5','dasdad,fsdfsdfsfsasada dasdasd','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','dasdasd','q231e','','0','','g','4','123123','dasdadwa','6.10','24f,8','f5,5','dasdad,fsdfsdfsfsasada dasdasd','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','','q231e','','0','','a','4','123123','dasdadwa','6.10','24f,8','f5,5','dasdad,fsdfsdfsfsasada dasdasd','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','','q231e','','','','a');
INSERT INTO yyy VALUES ('5','123123','dasdadwa','6.11','24f,9','f5,5','dasdad,fsdfsdfsfsasada dasdasd','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','dasdasd','q231e','','0','','g','5','123123','dasdadwa','6.11','24f,9','f5,5','dasdad,fsdfsdfsfsasada dasdasd','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','','q231e','','0','','a','5','123123','dasdadwa','6.11','24f,9','f5,5','dasdad,fsdfsdfsfsasada dasdasd','aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','','q231e','','','','a');
I must modify this text file so that each line can have a maximum of 50 characters. The problem is that I cannot simply put an endline after 50 characters because that would break the elements in those inserts, so I need to put the endline before the last comma.
For the first row it needs to be something like this:
INSERT INTO yyy VALUES ('1','123123','da,sdadwa',
'6.7','24f,5','f5,5',
'dasdad,fsdfsdfsfsasada dasdasd',
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
'dasdasd','q231e','','0','','g','1','123123',
'dasdadwa','6.7','24f,5','f5,5',
'dasdad,fsdfsdfsfsasada dasdasd','','','q231e','',
'0','','a','1','123123','dasdadwa','655.755',
'24f,5','f5,5','dasdad,fsdfsdfsfsasada dasdasd',
'','','q231e','','','','a');
As you can see there can be commas even inside the elements('da,sdadwa') which makes this a tad more difficult. I tried putting everything into arrays but I ran into some problems and couldn't get it to work.
What i tried:
if(is_array($testFileContents))
{
foreach($testFileContents as $line)
{
$j=0;
for($i=0;$i<=strlen($line);$i++)
{
//echo $line[$i];
$ct=1;
if($j==50)
{
if($line[$j]==",")
{
//$line[$j]=$line[$j].PHP_EOL;
}
else
{
$temporaryJ = $j;
while($line[$temporaryJ]!=",")
{
$temporaryJ--;
}
//$line[$temporaryJ] = $line[$temporaryJ].PHP_EOL;
//$j=$i-$ct*50;
$j=0;
$ct=$ct+1;
echo $ct." ";
}
}
else
{
$j++;
}
}
}
}
I know there has to be a much more simple way of going around this without using arrays but I cannot figure it out.
You can use preg_split() to split the lines. I found a pattern another user posted in this answer for matching values for an INSERT statement:
"~'(?:\\\\'|[^'])*'(*SKIP)(*F)|,~". This utilizes Special Backtracking Control Verbs.
You can play with the PHP code in this PhpFiddle.
foreach($lines as $line) {
$matches = preg_split("~'(?:\\\\'|[^'])*'(*SKIP)(*F)|,~",$line);
$currentIndex = 0;
$currentLine = '';
$outputLines = array();
$delimeter = ',';
while($currentIndex < count($matches)) {
if ($currentIndex == count($matches)-1 ) {
$delimeter = '';
}
$tempLine = $currentLine . $matches[$currentIndex] . $delimeter;
if (strlen($tempLine) <= 50) {
$currentLine .= $matches[$currentIndex] . $delimeter;
}
else {//push current line into array and start a new line
$outputLines[] = $currentLine;
$currentLine = $matches[$currentIndex] . $delimeter;
}
if ($currentIndex == count($matches)-1 ) {
$outputLines[] = $currentLine;
}
$currentIndex++;
}
//can use implode("\n",$outputLines) to write out to file
//or whatever your needs are
}
I have a file called "single.txt". The contents look like:
Array ( [0] => Ada Lovelace,F,96,ISTJ,Linux,24,99
[1] => Adele Goldberg,F,65,ENFJ,Windows,50,70
[2] => Alan Turing,M,41,ESTP,Mac OS X,31,50...
)
First, when a new person signs up, it adds them with them with their info to the end of the .txt file. I want to be able to check whether they've already signed up and I've written the following function:
function returnPerson($content){
global $person_name;
for($i=0 ; $i < count($content); $i++){
if($person_name == array_slice($content,0,0)){
$person = $content[$i];
return $person;
} else continue;
}
}
But that doesn't seem to be working.
How can I compare the first part of the string, i.e. the name part, to the name of the person checking?
Thanks!
Try something like this... you may have to modify it slightly depending on how your text is coming in, but should get you on the right track :)
function returnPerson($content){
global $person_name;
foreach($content as $profile) {
$profile = explode(',', $profile);
if ($person_name == $profile[0]) {
// Person Exists
return $profile;
}
}
return false; // person does not exist
}
You're "slicing" the same array while you're looping it. It looks like you just need a simple strpos():
if(strpos($content[$i], $person . ',') === 0){
return ...
}
Here's another way that doesn't require a for loop:
$names = array_map('reset', array_map('str_getcsv', $content));
if(in_array($person, $names)){
...
}
It works because your data seems to use the CSV format
You can loop over the elements in the array like this:
foreach ($content as $record) {
// $record now contains string "Ada Lovelace,F,96,ISTJ,Linux,24,99"
}
You can extract fields from a comma-separated string by using the explode() function:
$string = "Ada Lovelace,F,96,ISTJ,Linux,24,99";
$fields = explode(',', $string);
// $fields[0] now contains "Ada Lovelace"
// $fields[1] now comtains "F"
// ... etc
Putting those together, you'll get something like:
foreach ($content as $record) {
$fields = explode(',', $record);
if ($fields[0] == $name_to_check) {
// found it
}
}
// didn't find it