Converting static pages to dynamic pages using PHP and MySQL, Part 5

The challenge:

Take Adam Walker’s Carrajina dictionary (http://carrajina.conlang.org/dicthome.html) and stick it in a database so that Adam can add an entry whenever he wants without re-writing an html page and possibly messing up his html. One stricture is that Adam does not want to learn too much new stuff – no SQL, no PHP, just HTML. And if he can enter SAMPA and have it turn into IPA, that’s a plus!

Step 1 (data prep) is here, Step 2 (create database and load data) is here, and Step 3 (generating listings) is here. Part 4 on adding new entries is here. This is part 5.

Updating an entry uses the same form as adding an entry, but with the values pre-filled. Here is a screenshot of the form with an entry to edit. screenshot of edit-entry form

And here is the code to generate this form. First some code in the html head:

switch ($lang) {
   case 'eng':
      if ((isset($id)) && (is_numeric($id))) {
         $_SESSION['id'] = $id;
         $data = new EnglishEntry($mysqli, $id);
         $task = 'edit';
         $_SESSION['task'] = $task;
         $dbc = new EnglishController();
      }
   break;
   case 'car':
      if ((isset($id)) && (is_numeric($id))) {
         $_SESSION['id'] = $id;
         $data = new CarrajinaEntry($mysqli, $id);
         $task = 'edit';
         $_SESSION['task'] = $task;
         $dbc = new CarrajinaController();
      }
   break;
}
?>

Now for code in the body:

<!-- the big form -->
<form method="post" action="edit.php">
<?php
$term = null;
$pron = null;
$defs = null;

if (isset($data)) {
   $term = $data->getTerm();
   $pron = $data->getPron();
   $delforms[] = $dbc->formDelete($id, 'delentry',
      "Delete Full Entry "$term"");
   $defs = $data->getDefs();
}
?>
<!-- term and pronounciation -->
<p>
Word &nbsp; <input type="text" id="term" name="term"
value="<?php echo $term; ?>" />
&nbsp; Sampa or IPA &nbsp; <input
type="text" id="pron" name="pron" value="<?php echo $pron; ?>"
class="ipa" />
<span class="replace">click for ipa</span>
</p>

Easy enough. The $delforms array is used to hold delete links for each item that can be independently deleted.

<!-- definitions -->
<?php
$i = 1;
if (isset($defs)) {
   foreach ($defs as $defno => $defentry) {
      $delforms[] = $dbc->formDelete($defentry[0],
      'deldef', "Delete Def #$defno");
?>
<p>
Def # <input type="text"  class="num"
name="<?php echo "def[$defno][defno]"; ?>"
value="<?php echo $defno; ?>" />
&nbsp; POS <input type="text"
class="dp" name="<?php echo "def[$defno][pos]"; ?>"
value="<?php echo $defentry[1]; ?>" />
&nbsp; Definition Text
<textarea rows='3' cols='48' name="<?php echo
"def[$defno][deftext]"; ?>"><?php echo $defentry[2]; ?></textarea>
<input type="hidden" name="<?php echo "def[$defno][defid]"; ?>"
value="<?php echo $defentry[0]; ?>" />
</p>
<?php
      $i = $defno + 1;
   }
}
?>
<!-- add a definition -->
<div class="animate">
<p class="toggleable">New Definition +</p>
<div class="newitem">
<p>Def # <input type="text"  class="num"
name="<?php echo "def[$i][defno]"; ?>"  /> &nbsp; POS
<input type="text" class="dp" name="<?php echo "def[$i][pos]"; ?>" />
&nbsp; Definition Text <textarea rows='3' cols='48'
name="<?php echo "def[$i][deftext]"; ?>"></textarea>
</p>
</div>
</div>

This code prints definition form fields for each definition plus form fields for adding a new definition. The following adds the other form fields for English or for Carrajina entries.

<!-- extras -->
<!-- English first -->
<?php
if ($lang == 'eng') {
   //subentries
   $j = 1;
   if (isset($data)) {
      $subids = $data->getSubIDs();
      $count = count($subids);
      if ($count != 0) {
         foreach ($subids as $subid) {
            $sub = new EnglishEntry($mysqli, $subid);
            $sterm = $sub->getTerm();
            $spron = $sub->getPron();
            $delforms[] = $dbc->formDelete($subid, 'delsub',
               "Delete Subentry "$sterm"");
?>
<p>
Subentry <input type="text"
name="<?php echo "subentry[$j][sterm]"; ?>"
value="<?php echo $sterm; ?>" /> &nbsp; Sampa or IPA
<input type="text" name="<?php echo "subentry[$j][spron]"; ?>"
value="<?php echo $spron; ?>" class="ipa" />
<span class="replace">click for ipa</span>
<input type="hidden" name="<?php echo "subentry[$j][subid]"; ?>"
value="<?php echo $subid; ?>" />
</p>
<?php
            //subentry defs
            $defs = $sub->getDefs();
            $k = 1;
            if (!empty($defs)) {
               foreach ($defs as $defno => $defentry) {
                  $delforms[] = $dbc->formDelete($defentry[0],
                    'deldef', "Delete Subentry "$sterm" Def #$defno");
?>
<p>
Def # <input type="text"  class="num" value="<?php echo $defno; ?>"
name="<?php echo "subentry[$j][sdef][$defno][defno]"; ?>" />
&nbsp; POS <input type="text"  class="dp"
value="<?php echo $defentry[1]; ?>"
name="<?php echo "subentry[$j][sdef][$defno][pos]"; ?>"  />
&nbsp; Definition Text <textarea rows='3' cols='48'
name="<?php echo "subentry[$j][sdef][$defno][deftext]"; ?>"><?php
echo $defentry[2]; ?></textarea>
<input type="hidden"  value="<?php echo $defentry[0]; ?>"
name="<?php echo "subentry[$j][sdef][$defno][defid]"; ?>" />
</p>
<?php
               $k = $defno + 1;
            }//end foreach ($defs as $defno => $defentry)
         }//end if (!empty($defs))
?>
<div class="animate">
<p class="toggleable">New Subentry Definition +</p>
<div class="newitem">
<p>
Def # <input type="text"  class="num"
name="<?php echo "subentry[$j][sdef][$k][defno]"; ?>" />
&nbsp; POS <input type="text"  class="dp"
name="<?php echo "subentry[$j][sdef][$k][pos]"; ?>"  />
&nbsp; Definition Text <textarea rows='3' cols='48'
name="<?php echo "subentry[$j][sdef][$k][deftext]"; ?>"></textarea>
<input type="hidden"
name="<?php echo "subentry[$j][sdef][$k][defid]"; ?>" />
</p>
</div>
</div>
<?php
         $j++;
      }//end foreach ($subids as $subid)
   }//end if ($count != 0)
}//end if (isset($data))
?>
<!-- new subentry -->
<div class="animate">
<p class="toggleable">New Subentry +</p>
<div class="newitem">
<p>
Subentry <input type="text"
name="<?php echo "subentry[$j][sterm]"; ?>"  />
&nbsp; Sampa or IPA
<input type="text" name="<?php echo "subentry[$j][spron]"; ?>"
class="ipa" />
<span class="replace">click for ipa</span>
</p>
<p>
Def # <input type="text"  class="num"
name="<?php echo "subentry[$j][sdef][1][defno]"; ?>" />
&nbsp; POS  <input type="text"  class="dp"
name="<?php echo "subentry[$j][sdef][1][pos]"; ?>" />
&nbsp; Definition Text  <textarea rows='3' cols='48'
name="<?php echo "subentry[$j][sdef][1][deftext]"; ?>"></textarea>
</p>
</div>
</div>

<!-- Carrajina extras -->
<?php
} else if ($lang == 'car') {
   $etym = null;
   if (isset($data)) {
      $etym = $data->getEtymology();
   }//end if (isset($data))
?>
<!-- etymology -->
<p>Etymology   
<textarea rows='3' cols='48' name="etymology"><?php
echo $etym; ?></textarea>
</p>

<!-- Idioms -->
<p class="help">Idioms should be entered in lower case.</p>
<?php
   $idioms = null;
   $p = 1;
   if (isset($data)) {
      $idioms = $data->getIdioms();
      if (!empty($idioms)) {
         foreach ($idioms as $idiomentry) {
            $delforms[] = $dbc->formDelete($idiomentry[2],
              'delidiom',"Delete Idiom "$idiomentry[0]"");
?>
<p>
Idiom <input type="text" name="<?php echo "idioms[$p][idiom]"; ?>"
value="<?php echo $idiomentry[0]; ?>" />
&nbsp; Definition <textarea rows='3' cols='48'
name="<?php echo "idioms[$p][idiomdef]"; ?>"><?php
echo $idiomentry[1]; ?></textarea>
<input type="hidden"  name="<?php echo "idioms[$p][idiomid]"; ?>"
value="<?php echo $idiomentry[2]; ?>" />
</p>
<?php
            $p++;
         }//end foreach ($idioms as $idiomentry)
      }//end if (!empty($idioms))
   }//end if (isset($data))
?>
<!-- New idioms -->
<div class="animate">
<p class="toggleable">New Idiom +</p>
<div class="newitem">
<p>Idiom
<input type="hidden"  name="<?php echo "idioms[$p][idiomid]"; ?>"  />
<input type="text"  name="<?php echo "idioms[$p][idiom]"; ?>" />
&nbsp; Definition
<textarea rows='3' cols='48' name="<?php
echo "idioms[$p][idiomdef]"; ?>"></textarea>
</p>
</div>
</div>

<!-- Note -->
<?php
   $note = null;
   if (isset($data)) {
      $note = $data->getNote();
      if ($note[0] > 0) {
         $delforms[] = $dbc->formDelete($note[0], 'delnote',
            "Delete Note for "$term"");
      }
   }
?>
<p>
Note   
<input type="hidden" name="note[noteid]"
value="<?php echo "$note[0]"; ?>"  />
<textarea rows='3' cols='48' name="note[note]"><?php
echo "$note[1]"; ?></textarea>
</p>
<?php
}//end if lang
?>

<!-- Submit! -->
<p><input type="hidden"  name="task" value="<?php echo $task; ?>" />
<input type="hidden"  name="lang" value="<?php echo $lang; ?>" />
<!-- this will be blank for new entries -->
<input type="hidden" name="entryID"
value="<?php if (isset($id)) {echo $id;} ?>" />
<input type="submit" value="Submit!" /></p>
</form>

<!-- Now for those nasty deletes -->
<div>
<?php
if (isset($delforms)) {
   echo "<h2>Deletes</h2>";
   foreach ($delforms as $form) {
      echo $form;
   }
}
?>
</div>

That’s the form. One thing that might bite: Make sure there is no space or other characters between empty <textarea></textarea> code. If there is, the space will show up as a value when processing the data.

The code for processing updates is very similar to the code for processing adds.

public function updateEntry($mysqli, $entry) {
   $id = $this->sanitize($entry['entryID']);
   $term = $this->process($entry['term']);
   $pron = $this->process($entry['pron']);
   $etym = $this->process($entry['etymology']);
   $csort = $this->getSort($term);

   $query = "UPDATE carrajina_entry SET carrajina_sort=?,
      carrajina_term=?, carrajina_pronounciation=?,
      etymology=? WHERE carrajina_entryID =?";

   $stmt = $mysqli->stmt_init();
   if ($stmt = $mysqli->prepare($query)) {
      $stmt->bind_param("ssssi", $csort, $term, $pron, $etym, $id);
      $stmt->execute();
      $stmt->close();
   }

   //update defs and add new defs for entry, if
   foreach ($entry['def'] as $def) {
      if (!empty($def['defid'])) {
         $this->updateCardefs($mysqli, $def);
      } else {
         $this->addDefs($mysqli, $def, $id);
      }
   }

   //update idioms, if and add new, if
   if (isset($entry['idioms'])) {
      foreach ($entry['idioms'] as $idiom) {
         if (!empty($idiom['idiomid'])) {
            $this->updateIdioms($mysqli, $idiom);
         } else {
            $this->addIdioms($mysqli, $idiom, $id);
         }
      }
   }

   //update note, if
   if (!empty($entry['note']['noteid'])) {
      $noteid = $this->process($entry['note']['noteid']);
      $note = $this->process($entry['note']['note']);

      $query = "UPDATE carrajina_note SET note=? WHERE noteID =?";

      $stmt = $mysqli->stmt_init();
      if ($stmt = $mysqli->prepare($query)) {
         $stmt->bind_param("si", $note, $noteid);
         $stmt->execute();
         $stmt->close();
      }
   } else if (!empty($entry['note']['note'])) {
      $this->addNote($mysqli, $entry['note'], $id);
   } else {
      //nada
   }

   return $id;
}

And that is pretty much it. I enjoyed doing this and I think Adam enjoyed having it done. 🙂

10 PHP string functions

Here are 10 useful PHP string functions.

$string = "Hello World";

1, 2, 3: trim() along with ltrim() and rtrim() strip characters from a string. trim($string) without any further arguments will strip all spaces, carriage returns, new lines, null characters, and vertical tabs from $string.

echo trim($string, 'ld');

returns “Hello Wor” because trim() only trims the edges of a string. ltrim() trims from the left only, rtrim() from the right only, and trim() from both edges.

4: str_replace() replaces all instances of a given character with another. To strip out all ‘l’s from our string, use

echo str_replace('l', '', $string);

This returns “Heo Word”.

5, 6: strtolower() transforms a string into all lower-case letters.

echo strtolower($string);

returns “hello world”. strtoupper() makes everything upper case – “HELLO WORLD”.

7: strlen() returns the length of a string.

echo strlen($string);

returns “11”. This can be a useful way to check if you have the right string.

8: substr() returns a portion of the string. It helps to know the length of the string, because

echo substr($string, 3);

will start at the 4th character (or after the 3rd, if that’s easier for you) in the string and continue to the end, returning “lo World”.

echo substr($string, 10);

will return “d”. One can use negative numbers:

echo substr($string, -1);

will also return “d”. Here substr() starts at the end of the string and returns one character.

echo substr($string, -3);

return “rld”. You can also specify a length for substr() to return.

echo substr($string, 0, 3);

returns “Hel”. It starts at position 0, and returns 3 characters. Lengths can be negative. Though with a negative length, the beginning point is the end of the word.

echo substr($string, 0, -3);

returns “Hello Wo”.

echo substr($string, 1, -3);

removes the first character (i.e. it starts after the first character, and removes the last three characters, returning “ello Wo”.

9, 10: strpos() finds the first position of a character in a string.

echo strpos($string, 'l');

returns “2”. “H” is position 0, “e” is position 1, and “l” is position 2 (and 3, and 9). strpos() is case-sensitive. stripos() is the equivalent case-insensitive function.