LAMP Programming in PHP
A quick review of the PHP language[edit]
Syntax[edit]
Mixing code and template[edit]
- PHP pages mix code and display into a single page.
- Markup starts as standard HTML.
- Break into using <?php ...php code... ?>.
- Use <?= ...php expression... ?> as shorthand to insert an expression into output.
Code Syntax[edit]
- Syntax is similar to C or Perl.
- Commands are separated by semi-colons.
- Closing tag counts as a semi-colon.
- Curly braces surround code blocks.
- Comments use any common format:
- // This is a comment.
- /* This is a muliline comment. */
- # This is a shell style comment.
Sample[edit]
<html>
<head>
<title>Example PHP page</title>
</head>
<body>
<?php
// This function will be run on the server
function foo() {
return "World";
}
/* This
is
a
comment */
?>
<h1>Hello, <?= foo() ?></h1>
</body>
</html>
Data Types[edit]
- Variables are prefixed with a dollar sign (eg: $foo)
Scalars[edit]
- Represents a single value.
- Boolean (eg: true, FALSE, tRuE)
- Number (eg: 42, 3.141592653, 0xFF, -1)
- String (eg: "foo", 'bar', "baz\n", "Hello, $foo")
- Strings expand variables
- Concatenate strings with . not +
- NULL
Arrays[edit]
- Represents a collection of values.
- Unlike other languages, all PHP arrays are associative.
- Created using array() function
- array() - empty array.
- array(1,2,3) - array containing 1, 2, 3 with indexes 0, 1, 2.
- array('foo'=>1, 'bar'=>2, 'baz'=>3) - array containing 1, 2, 3 with indexes foo, bar, baz.
- array('foo'=>1, 2) - array containing 1, 2 with indexes foo and 0.
- Indexes can only be integers or strings. Other types will be converted.
- Assigning arrays is a copy operation, use references.
Sample[edit]
<pre>
<?php
$a = true;
$b = 12;
$c = "Hello, World!";
$d = NULL;
$e = array($a,$b,'foo'=>$c,'bar'=>$d);
echo("$e[0]\n"); // Prints true
echo("$e[1]\n"); // Prints 12
echo($e['foo']."\n"); // Prints Hello, World!
echo("$e[bar]\n"); // Prints nothing
echo("$e\n"); // Prints Array
?>
</pre>
Variable Scope[edit]
Unlike other scripting languages like perl, all variables are local to their code block. To reference variables in an above scope use the global keyword.
<?php
$a = 1;
$b = 2;
$c = 3;
function foo() {
global $b;
$c = 4;
echo($a); // Prints nothing
echo($b); // Prints 2
echo($c); // Prints 4
}
foo();
echo($c); Still prints 3, foo didn't modify.
?>
Operators[edit]
- Arithmetic
- +, -, /, * (plus, minus, divide, multiply)
- ++, -- (increment, deincrement)
- % (modulus)
- Assignment
- = (set equal to)
- +=, -=, *=, /= (plus-equal, minus-equal, ...)
- .= (concatenate)
- %= (modulus)
- Compare
- ==, <=, >=, <, > (equals, less than or equal to, ...)
- === (is exactly - "1" === 1 is false.)
- String
- . (concatenate a string)
- Logical
- && (and)
- || (or)
- ! (not)
Statements[edit]
<pre>
<?php
// If-Else (anything non-false is true)
if (true && 1 && "foo" && "false") {
echo("This executes\n");
}
else {
echo("This does not\n");
}
// If-Elseif (only these things are false)
if (false || 0 || NULL || "") {
echo("This does not execute\n");
}
elseif (true) {
echo("This does\n");
}
// For loop
for ($x=0; $x<10; $x++) {
echo("This executes 10 times\n");
}
// While loop
$x=10
while ($x>0) {
echo("This also executes 10 times\n");
$x--;
}
// Foreach loop iterates over an array
things = array(1,2,3,4,5,6,7,8,9,10);
foreach($things as $thing) {
echo("Thing is $thing\n"); // Prints 1-10
}
// Foreach loop also iterates associatively
things = array(one=>1, two=>2, three=>3);
foreach($things as $key => $value) {
// Prints one is 1, two is 2, three is 3.
echo("$key is $value\n");
}
// Break leaves a looping block
while(true) {
break; // Won't loop forever
}
// Continue restarts at the top
for($x=0; $x<10; $x++) {
echo("$x\n");
continue; // Jump to the next iteration
echo($x/0); // Divide by zero -- won't run!
}
?>
Commonly used functions[edit]
PHP has so many functions. Much of it is very non-OOP, preferring to litter the global namespace with lots and lots of functions. Functions available vary on how PHP was compiled, use phpinfo() to see that information. Here's some common ones.
- Array functions
- count($array) - Number of items in an array
- sort($array) - Sort an array
- ksort($array) - Sort an associative array by key
- array_push($array,$item) - Push an item onto the end of the array
- array_pop($array) - Pop a item off the end of the array
- array_unshift($array,$item) - Add an item onto the beginning of the array
- array_shift($array) - Shift the first item off the array
- Output functions
- echo($a[,$b,...]) - Prints something to the web output
- printf($format[,$a,...]) - Formatted printing
- print_r($a) - Recursively output a data structure
- String functions
- chop($string) - Removes the last character from a string
- sprintf($format[,$a...]) - Format a string
- strtolower($string)
- strtoupper($string)
- ucfirst($string)
- ucwords($string)
- strip_tags($string)
- join($delmiter,$array)
- str_split($delimiter,$string)
- Regular expression functions
- preg_match($pattern,$string)
- preg_replace($pattern,$replacement,$string)
- preg_split($patter,$string)
- Misc
- die($message) - Abort with error
- exit($message) - Exit with message
- eval($code) - Execute arbitrary code (careful!)
- phpinfo() - Spits out lots of information about your PHP install, don't leave this lying around.
User-defined functions[edit]
function foo($bar, $baz) {
// Code
return $result;
}
Objects[edit]
<?php
class A
{
function foo()
{
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ")\n";
} else {
echo "\$this is not defined.\n";
}
}
}
class B
{
function bar()
{
A::foo();
}
}
$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
?>
Processing Web Forms[edit]
GET and POST requests[edit]
- GET requests are for non-modifying requests, like searches
- GET requests send variable information in the URL
- GET requests are cachable
- use $_GET['key'] to access GET variables
- POST requests are for modifying requests, like a sign up form
- POST requests send variable information in the HTTP body
- POST requests should not be cached
- use $_POST['key'] to access POST variables
- $_REQUEST['key'] will get from either GET or POST or COOKIES. Maybe that's a bad idea.
- $_SERVER['REQUEST_METHOD'] will tell you if it's a GET or POST.
Forms[edit]
- The form tag defines a block of form elements to submit
- method="GET" or method="POST"
- action="url to submit to"
- enctype is useful if you're sending files
- Form elements
- Form elements all have a name attribute, this is the key the element is submitted as
- Form elements should also include an id attribute, so javascript can address them
- The input tag is the most basic form element, the type attribute controls how it works
- type="text" - A standard text box
- type="password" - A standard text box but the characters are obscured
- type="hidden" - A hidden form element, useful for behind the scenes data
- type="checkbox" - A check box. If unchecked nothing is submitted for this key
- type="radio" - A radio button. Include multiple of these with the same name
- type="submit" - The submit button, every form should include one. This sends the form.
- type="image" - A submit button with an image for the button.
- The value attribute controls the default value
- The size attribute controls the size of the element
- The textarea tag is for a big block of text.
- Use rows and cols to control the size of the textarea
- Use the wrap to control word wrapping. You probably want wrap="soft"
- The select tag is a section list.
- Use an option tags within the select tag for each list item
Example[edit]
<?php
$error = NULL;
function authenticate($username, $password) {
// magic authentication code here
}
// If the request is POST and the Login button was clicked
if ($_SERVER['REQUEST_METHOD']=='POST' && $_POST['submit'] == "Login") {
if (authenticate($_POST['username'],$_POST['password'])) {
// Send the user back to the page they came from.
header("Location: $_POST['return_url']");
}
else {
$error = "Incorrect username or password.";
}
}
?>
<h1>My Simple Login Form</h1>
<?php
// If the form processed has an error, print it out here.
if ($error) {
echo("<div class='error'>$error</div>");
}
?>
<!-- $_SERVER['PHP_SELF'] is the url to this very form -->
<form method="POST" action="<?= $_SERVER['PHP_SELF'] ?>">
<p>
<label for="username">Username:</label><br />
<input type="text" id="username" name="username" size="30" />
</p>
<p>
<label for="password">Password:</label><br />
<input type="password" id="password" name="password" size="30" />
</p>
<p>
<!-- remember will be true if checked, NULL if not -->
<input type="checkbox" id="remember" name="remember" value="true" />
<label for="remember">Remember me</label>
</p>
<p>
<!-- The submit button sends data too. The value is the label of the button. -->
<input type="submit" id="submit" name="submit" value="Login" />
</p>
<!-- The page to send the user back to. Check out the short cicruit. Notice REFERER is mispelled. -->
<input type="hidden" id="return_url" name="return_url"
value="<?= $_GET['return_url'] ? $_GET['return_url'] : $_SERVER['HTTP_REFERER'] ?>"
/>
</form>
Stateless programming[edit]
- HTTP is a stateless protocol
- That means every request is a fresh start for your program
- We use cookies and post back information to keep track of who and what's going on
- Thankfully PHP has a handy session management system that abstracts this all away
Example[edit]
<?php
// Starts/Restores session
session_start();
// Clear the session if user sends reset
if ($_GET['reset']) {
// Unset all of the session variables.
$_SESSION = array();
// If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data!
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time()-42000, '/');
}
// Finally, destroy the session.
session_destroy();
}
if (!isset($_SESSION['count'])) {
$_SESSION['count'] = 0;
}
else {
$_SESSION['count']++;
}
?>
<p>You have visited this page <?= $_SESSION['count'] ?> times.</p>
<p><a href="<?= $_GLOBAL['PHP_SELF'] ?>?reset=1">Reset Counter</a></p>
Secure user-input[edit]
- Never allow user input to be echoed back onto the page as-is.
- Someone can mess up the design of your page by inserting HTML
- Someone can steal your users cookies by inserting Javascript
- Use strip_tags($string) to remove all HTML
- Use strip_tags($string,$allowable_tags) to most HTML.
- Careful, this doesn't remove attributes so I can use onmouseover to hack your site.
$username = strip_tags($_POST['username']);
$about = strip_tags($_POST['about'],"a,b,u,i,strong");
## Strip out attributes using regular-expressions.
$about = preg_replace("/<(\w+)\s+.*?>/",'<$1>',$about);
Storing data[edit]
Using files[edit]
Writing[edit]
// Append some data to a file.
$handle = fopen("/secure/location/file.txt","a");
fputs($handle, $data);
fclose($handle);
// Slurp up an entire file
$data = file_get_contents("/secure/location/file.txt");
Using JSON[edit]
- JSON is a handy way to encode data to pass to a browser for AJAX calls, and to store on disk if we're not using a real database.
function write_new_user($username, $password, $first_name, $last_name, $email) {
$data = array(
"username" => $username,
"password" => md5($password),
"first_name" => $first_name,
"last_name" => $last_name,
"email" => $email
);
$handle = fopen("/secure/location/users.txt","a");
puts($handle,json_encode($data));
flclose($handle);
}
function read_users() {
}
Security[edit]
- Make sure you write your files somewhere secure -- Don't put them in a directory accessible on the web!
- Be real careful with your filenames. Never allow user input to influence the filename without validation.
- I like to pass all filenames and paths through lookup tables or configuration files to make extra sure.
Using MySQL[edit]
CREATE TABLE[edit]
CREATE TABLE users (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(50) NOT NULL,
first_name VARCHAR(50),
last_name VARCHAR(50),
email VARCHAR(50) NOT NULL,
last_seen DATETIME
UNIQUE(username),
INDEX(username,password),
INDEX(last_seen)
);
## Create a posts table
INSERT[edit]
INSERT INTO some_table (column1, column2, column2) VALUES ("foo","bar","baz");
# OR YOU CAN DO THIS
INSERT INTO some_table SET foo=1, bar="two", baz=1+1+1;
INSERT INTO users (username, password, email) VALUES ("justin","doifjsdofijsd","[email protected]");
UPDATE[edit]
UPDATE users SET last_seen=NOW() WHERE id=1234;
## CAREFUL!
UPDATE users SET password=MD5(?);
DELETE[edit]
DELETE FROM users WHERE id=1234;
- I HATE DELETE -- WHY NOT THIS INSTEAD??
UPDATE users SET deleted=1 WHERE id=1234;
SELECT[edit]
## Easy authentication!
SELECT username, email, first_name, last_name FROM users WHERE username=? AND password=MD5(?);
## Give me all users in order of last sign on
SELECT id,username FROM users ORDER BY last_seen DESC;
## That's too many users, how about this instead
SELECT id,username FROM users ORDER BY last_seen DESC LIMIT 0,30;
## Page 3
SELECT id,username FROM users ORDER BY last_seen DESC LIMIT 60,30;
## JOINS combine table from two or more tables
## LIKE does a substring search, the % is a wildcard.
SELECT posts.id AS posts_id, posts.title, users.id AS users_id, users.username
FROM posts
JOIN users ON posts.users_id=users.id
WHERE posts.title LIKE CONCAT('%',?,'%')
Do it in PHP[edit]
- If you can, use mysqli!
function get_mysql_connection() {
$host="localhost";
$port=3306;
$socket="/var/run/mysqld/mysqld.sock";
$user="justin";
$password="password";
$dbname="justin";
$conn = new mysqli($host, $user, $password, $dbname, $port, $socket)
or die ('Could not connect to the database server' . mysqli_connect_error());
return $conn;
}
function write_user($username, $password, $first_name, $last_name, $email) {
$conn = get_mysql_connection();
$stmt = $conn->prepare(
"INSERT INTO users (username,password,first_name,last_name,email) " .
"VALUES (?,MD5(?),?,?,?);"
);
$stmt->bind_param('sssss',$username,$password,$first_name,$last_name,$email);
$rows_affected = $stmt->execute();
return $rows_affected; // Should be 1 if all goes well.
}
function write_post($users_id, $title, $body) {
// Write this function
}
Security[edit]
function get_mysql_connection() {
$host="p:localhost";
$port=3306;
$socket="/tmp/mysql.sock";
$user="root";
$password="password";
$dbname="test";
$conn = new mysqli($host, $user, $password, $dbname, $port, $socket)
or die ('Could not connect to the database server' . mysqli_connect_error());
return $conn;
}
function write_user($username, $password, $first_name, $last_name, $email) {
$conn = get_mysql_connection();
$rows_affected = $conn->query(
"INSERT INTO users (username,password,first_name,last_name,email) ".
"VALUES ('$username',MD5('$password'),'$first_name','$last_name','$email'"
);
return $rows_affected; // Should be 1 if all goes well.
}
- Look how much easier that is! What happens if my username is "; DELETE FROM users;" though?!
How NOT to use MySQL[edit]
- Don't over rely the database.
- It's first job is to be correct, it's second job is to be fast.
- You know your data better!
- Sometimes it's better to do things in code.
- INDEX things that you'll use in the WHERE part of a query.
- Learn to love EXPLAIN!
- NEVER EVER EVER ALLOW UNVALIDATED USER INPUT IN QUERIES
The Uber Example[edit]
<?php
$VALIDATION_ERRORS = array();
function get_mysql_connection() {
$host="localhost";
$port=3306;
$socket="/var/run/mysqld/mysqld.sock";
$user="justin";
$password="day";
$dbname="justin";
$conn = new mysqli($host, $user, $password, $dbname, $port, $socket)
or die ('Could not connect to the database server' . mysqli_connect_error());
return $conn;
}
function write_user($username, $password, $first_name, $last_name, $email) {
$conn = get_mysql_connection();
$stmt = $conn->prepare(
"INSERT INTO users (username,password,first_name,last_name,email) " .
"VALUES (?,MD5(?),?,?,?);"
);
$stmt->bind_param('sssss',$username,$password,$first_name,$last_name,$email);
$rows_affected = $stmt->execute();
// TODO FIXME Return LAST_INSERT_ID() instead!
return $rows_affected; // Should be 1 if all goes well.
}
function get_user_by_username($username) {
$conn = get_mysql_connection();
$stmt = $conn->prepare("SELECT id,username,email,first_name,last_name FROM users WHERE username=? LIMIT 1");
$stmt->bind_param('s',$username);
$stmt->execute();
$stmt->bind_result($users_id,$username,$email,$first_name,$last_name);
if ($stmt->fetch()) {
return array("users_id"=>$users_id,"username"=>$username,"email"=>$email,"first_name"=>$first_name,"last_name"=>$last_name);
}
else {
return NULL;
}
}
function get_user_by_username_password($username,$password) {
$conn = get_mysql_connection();
$stmt = $conn->prepare("SELECT id,username,email,first_name,last_name FROM users WHERE username=? AND password=MD5(?) LIMIT 1");
$stmt->bind_param('ss',$username,$password);
$stmt->execute();
if ($stmt->fetch()) {
return array("users_id"=>$users_id,"username"=>$username,"email"=>$email,"first_name"=>$first_name,"last_name"=>$last_name);
}
else {
return NULL;
}
}
function write_post($users_id, $title, $body) {
$conn = get_mysql_connection();
$stmt = $conn->prepare(
"INSERT INTO posts (posted_on, users_id, title, body) ".
"VALUES (NOW(), ?, ?, ?);"
);
$stmt->bind_param("dss",$users_id,$title,$body);
$stmt->execute();
// TODO FIXME Add SELECT LAST_INSERT_ID() call to get new posts.id
}
function echo_sign_in_area() {
echo('<div id="SignInArea">');
if ($_SESSION['username']) {
echo('Welcome ' . $_SESSION['username'] . '. <a href="'.$_SERVER['PHP_SELF'].'?command=Sign+Out">Sign Out</a>');
}
else {
echo('<a href="javascript:promptToSignIn();">Sign In</a>');
echo(' or ');
echo('<a href="javascript:promptToSignUp();">Sign Up</a>');
}
echo('</div>');
}
function echo_blog_entry($posts_id, $users_id, $username, $posted_on, $title, $body) {
echo("<div id='BlogEntry$posts_id' class='BlogEntry'>");
echo("<div class='Title'>$title</div>");
echo("<div class='Meta'>Written by <a href='view_user.php?users_id=$users_id'>$username</a> on $posted_on.</div>");
echo("<div class='Body'>$body</div>");
echo("</div>");
}
function echo_blog_entries() {
$conn = get_mysql_connection();
$rows = $conn->query(
"SELECT id AS posts_id, posted_on, title, body, users.id AS users_id, username ".
"FROM posts JOIN users ON posts.users_id=users.id " .
"ORDER BY posted_on DESC ".
"LIMIT 10"
);
if (!$rows)
return;
while($row = $rows->fetch_assoc()) {
echo_blog_entry(
$row['posts_id'],
$row['users_id'],
$row['username'],
$row['posted_on'],
$row['title'],
$row['body']
);
}
}
function set_validation_error($id,$error) {
global $VALIDATION_ERRORS;
$VALIDATION_ERRORS[$id] = $error;
}
function echo_validation_error($id) {
global $VALIDATION_ERRORS;
if ($VALIDATION_ERRORS[$id]) {
echo("<div id='".$id."Error' class='Error'>".$VALIDATION_ERRORS[$id]."</div>");
}
else {
// Put a hidden error there for client-side validation
echo("<div id='".$id."Error' class='Error' style='display:none'></div>");
}
}
function process_command() {
switch($_REQUEST['command']) {
case "Sign Up":
process_sign_up();
break;
case "Sign In":
process_sign_in();
break;
case "Sign Out":
process_sign_out();
break;
default:
break;
}
}
function validate_sign_up() {
$result = TRUE;
if (!$_POST['username']) {
set_validation_error('username','Username is required');
$result = FALSE;
}
$user = get_user_by_username($_POST['username']);
if ($user) {
set_validation_error('username','That username has already been taken.');
$result = FALSE;
}
if (!$_POST['password']) {
set_validation_error('password','Password is required');
$result = FALSE;
}
if ($_POST['repeat'] != $_POST['password']) {
set_validation_error('repeat','Passwords do not match');
$result = FALSE;
}
if (!$_POST['email']) {
set_validation_error('email','Email is required');
$result = FALSE;
}
return $result;
}
function process_sign_up() {
if (validate_sign_up()) {
write_user(
$_POST['username'],
$_POST['password'],
$_POST['first_name'],
$_POST['last_name'],
$_POST['email']
);
$_SESSION['username'] = $_POST['username'];
}
}
function process_sign_in() {
$user = get_user_by_username_password($_POST['username'],$_POST['password']);
if (!$user) {
set_validation_error('username','Incorrect username or password');
}
$_SESSION['username'] = $user['username'];
}
function process_sign_out() {
$_SESSION['username'] = NULL;
}
session_start();
process_command();
?>
<html>
<head>
<title>Welcome to my SimpleBlog!</title>
<!--<script type="text/javascript" src="jquery-latest.js"></script>-->
<script type="text/javascript">
function getElement(id) {
return document.getElementById(id);
}
function getValue(id) {
return getElement(id).value;
}
function promptToSignIn() {
// Hide the sign up elements
getElement("SignUp").style.display="none";
// Set the action to be signing in
getElement("SignInSubmit").value="Sign In";
// Show the sign in popup
getElement("SignInPopup").style.display="block";
// Focus on username
getElement("username").focus();
}
function promptToSignUp() {
// Show the sign up elements
getElement("SignUp").style.display="block";
// Set the action to be signing in
getElement("SignInSubmit").value="Sign Up";
// Show the sign in popup
getElement("SignInPopup").style.display="block";
// Focus on username
getElement("username").focus();
}
function setValidationError(id,error) {
var element = getElement(id + 'Error');
element.innerHTML = error;
element.style.display = "block";
}
function validateSignInForm() {
var result = true;
if (!getValue('username')) {
setValidationError('username','Username is required');
result = false;
}
if (!getValue('password')) {
setValidationError('password','Password is required');
result = false;
}
if (getValue('SignInSubmit') == 'Sign Up') {
if (getValue('repeat') != getValue('password')) {
setValidationError('repeat','Passwords do not match');
result = false;
}
if (!getValue('email')) {
setValidationError('email','Email is required');
result = false;
}
}
return result;
}
</script>
<style type="text/css">
.PopUp {
display: none;
position: absolute:
top: 30px;
width: 350px;
margin: auto;
padding: 10px;
min-height: 50px;
background-color: #ccc;
border: 3px solid #999;
}
.PopUp th {
width: 150px;
text-align: left;
}
#BlogPostPopup {
width: 600px;
}
.Error {
color: red;
font-weight: bold;
}
.Required {
font-weight: bold;
color: red;
}
</style>
</head>
<body>
<div id="Heading">
<h1>Welcome to my SimpleBlog!</h1>
<?php echo_sign_in_area(); ?>
</div>
<div id="Main">
<?php echo_blog_entries(); ?>
</div>
<div id="SignInPopup" class="PopUp">
<form id="SignInForm" method="POST" action="<?= $_SERVER['PHP_SELF'] ?>" onsubmit="return validateSignInForm()">
<table>
<tr>
<th><label for="username" class="Required">Username:</label></th>
<td>
<input type="text" id="username" name="username" size="30" />
<?php echo_validation_error("username") ?>
</td>
</tr>
<tr>
<th><label for="password" class="Required">Password:</label></th>
<td>
<input type="password" id="password" name="password" size="30" />
<?php echo_validation_error("password") ?>
</td>
</tr>
</table>
<table id="SignUp">
<tr>
<th><label for="repeat" class="Required">Repeat:</label></th>
<td>
<input type="password" id="repeat" name="repeat" size="30" />
<?php echo_validation_error("repeat") ?>
</td>
</tr>
<tr>
<th><label for="email" class="Required">Email:</label></th>
<td>
<input type="text" id="email" name="email" size="30" />
<?php echo_validation_error("email") ?>
</td>
</tr>
<tr>
<th><label for="first_name">First Name:</label></th>
<td>
<input type="text" id="first_name" name="first_name" size="30" />
<?php echo_validation_error("first_name") ?>
</td>
</tr>
<tr>
<th><label for="last_name">Last Name:</label></th>
<td>
<input type="text" id="last_name" name="last_name" size="30" />
<?php echo_validation_error("last_name"); ?>
</td>
</tr>
</table>
<table>
<tr>
<th> </th>
<td><input type="submit" id="SignInSubmit" name="command" value="Sign In" />
</tr>
</table>
</form>
</div>
<div id="BlogPostPopup" class="PopUp">
</div>
</body>
</html>