PHP

From CSE330 Wiki
Jump to navigationJump to search

PHP is an open-source language used widely for writing server-side code for web servers. PHP is a good starting point for web developers, as it is straightforward to learn and yet powerful at the same time. Indeed, some of the internet's most popular web sites are written using PHP as their language of choice! This article introduces the syntax of PHP and how to make a basis PHP web application.

Why use a server-side scripting language?

Server-side scripting languages like PHP are what turn your web site from a static fileserver to a dynamic web application.

By default, Apache only knows how to serve static HTML pages to the client. You can write as many HTML pages as you want, which is fine for basic web sites. But if you want to have users post to a forum, or process credit card transactions, or make your own online calendar, a server-side language like PHP is what you need.

Installing PHP

To install PHP, you need both the PHP interpreter and the Apache module that runs PHP code. In yum, the package name is php; in Debian, there are two packages: php5 and libapache2-mod-php5.

Once you install the required packages, restart Apache for the changes to take effect.

PHP Configurations

The PHP configuration file is called php.ini. In RHEL, it is located at /etc/php.ini; in Debian, it is located at /etc/php5/apache2/php.ini.

The configuration file is largely self-documenting as to what the different options mean. There is one value in particular that we want to change for the purposes of CSE330. Open php.ini in your favorite text editor, find the display_errors option, and set it to On:

display_errors = On

You will need to restart Apache for any php.ini changes to take effect.

Note: You can turn errors on or off for a certain PHP script by using the error_reporting() and/or ini_set() functions.

Note: If you tell PHP to log its errors, they will be stored in the Apache error log file, at /var/log/httpd/error_log in RHEL or /var/log/apache2/error.log in Debian.

Your First PHP Script

By default, all files that have the *.php extension will be interpreted as containing PHP code. Here is the most basic PHP script:

<?php
phpinfo();
?>

Save that code into a file named phpinfo.php, and save it in your web server directory. Load it up in your browser like this: http://ec2-blah-blah.compute-1.amazonaws.com/phpinfo.php

If you see something like this, your PHP installation is working!

Php info.png

Look at the source code of that page. Notice that even though there were only three lines of code in our PHP file, PHP filled it up with hundreds of lines of HTML!

Your own PHP scripts will probably look something more like this:

<!DOCTYPE html>
<html>
<head>
	<title>My First PHP Script</title>
</head>
<body>
<?php
echo "\t<p>Hello World!</p>\n";
?>
</body>
</html>

The above code will send the following HTML to the browser:

<!DOCTYPE html>
<html>
<head>
	<title>My First PHP Script</title>
</head>
<body>
	<p>Hello World!</p>
</body>
</html>

Here's the take-home message of this section. To run PHP code, enclose it in <?php ?> tags; HTML code can be used in a PHP file (although not inside the PHP code block!); and just a few lines of code can generate an arbitrary amount of HTML.

PHP Language Components

PHP is a programming language much like others you have learned: it has variables, arrays, functions, objects etc. However, the syntax for PHP and the way PHP handles variables may be new to you. This section gives an overview of PHP the language.

Variables

All variables start with the currency $ symbol. The $ is necessary for both setting and accessing.

PHP is a weak-typed language; that is, you can set any type of value to a variable (string, array, number, etc), and PHP will accept it, even if that variable previously contained a different data type. In some ways this is convenient, but in others it can lead to hard-to-detect bugs, so be careful.

<?php
$i = 5;  # Set the integer 5 to the variable $i
$msg = "Hello World";  # Set the string Hello World to the variable $msg
?>

Notice that all lines in PHP necessarily end with a semicolon. If you forget a semicolon, the PHP will fail to parse!

Strings

Strings in PHP can be either single-quoted or double-quoted. Single-quoted strings are always taken literally; double-quoted strings allow for additional elements.

<?php
$a = "Apple";
$b = "Banana";

$fruits_double = "$a\n$b";   # $fruits_double now contains the string Apple (line break) Banana
$fruits_single = '$a\n$b';   # $fruits_single now contains the string $a\n$b
?>

If you want to use special characters in a double-quoted strings, escape them using the backslash operator:

<?php
$a = "Apple";
$b = "Banana";

$fruits = "\$a\\n$b";   # $fruits now contains the string $a\nBanana
?>

You can concatenate multiple strings together using the concatenation operator, which in php is a period:

<?php
$c = "Cherry";
$g = "Grapefruit";

$fruits = $c."\n".$g;   # $fruits contains the string Cherry (line break) Grapefruit
?>

Arrays

Declaring arrays is very simple in PHP.

<?php

$fruits = array("Apple", "Banana", "Cherry", "Grapefruit");   # $arr now contains an array with 4 items

echo $fruits[1];   # displays Banana

echo count($fruits);   # displays 4

array_shift($fruits);   # remove the first element of the array

echo $fruits[1];   # displays Cherry

echo count($fruits);   # displays 3

?>

Note: echo outputs a string to the browser. We will see more ways to output data later in this guide.

PHP also supports associative arrays. Associative arrays are arrays whose keys are strings rather than numbers; in some languages, they are called Dictionaries.

<?php

$fruits["a"] = "Apple";
$fruits["b"] = "Banana";
$fruits["c"] = "Cherry";
$fruits["g"] = "Grapefruit";

echo $fruits["b"];   # displays Cherry

$keys = array_keys($fruits);   # get an array containing indexed values of the fruits' keys

echo $keys[3];   # displays g

?>

Conditional Statements

Conditional statements work similarly to how they do in other languages.

<?php
$grade = 85;

if ($grade < 60) {
	echo "F";
} elseif ($grade < 70) {
	echo "D";
} elseif ($grade < 80) {
	echo "C";
} elseif ($grade < 90) {
	echo "B";
} else {
	echo "A";
}
?>

PHP also supports switch statements, which are convenient for simplifying long if/elseid/else blocks:

<?php
$food = "Apple";

switch ($food) {

case "Apple":
case "Banana":
case "Cherry":
case "Grapefruit":
	echo "You must like fruit!";
	break;
case "Broccoli":
case "Spinach":
	echo "You must like vegetables!";
	break;
default:
	echo "You don't like fruits or vegetables!";
	break;

}
?>

Loops

PHP supports several different kinds of loops, including while, for, and foreach:

<?php

$mystring = "";
$i = 0;
while ($i < 5) {
	$mystring .= "Blah";
}
echo $mystring;   # displays BlahBlahBlahBlahBlah


$myarray = array("Apple", "Banana", "Cherry", "Grapefruit");

# The following two loops are functionally equivalent.

$mystring = "";
for($i=0; $i<count($myarray); $i++){
	$mystring .= $i.": ".$myarray[$i].", ";
}
echo $mystring;   # displays 0: Apple, 1: Banana, 2: Cherry, 3: Grapefruit

$mystring = "";
foreach($myarray as $key => $value){
	$mystring .= $key.": ".$value;
}
echo $mystring;   #displays 0: Apple, 1: Banana, 2: Cherry, 3: Grapefruit

?>

Functions

Just like with all modern programming languages, you can define your own functions with PHP.

<?php

function add($x, $y){
	return $x + $y;
}

echo add(3, 5);   # displays 8

?>

A neat shortcut for PHP is that you can specify default parameter values directly in the argument list:

<?php

function sayHello($name="John Doe"){
	return "Hello, $name... how do you do?";
}

echo sayHello("Todd");   # displays Hello, Todd... how do you do?
echo sayHello();   # displays Hello, John Doe... how do you do?

?>

Object-Oriented Programming

PHP5 supports object-oriented programming, and many new libraries come as classes rather than simple functions. Here is an example class definition:

<?php

class Food {
	protected $name;
	
	function __construct($name){
		$this->name = $name;
	}
	
	static function getDefinition(){
		return "Food is nourishment for carbon-based lifeforms.";
	}
	
	function getName(){
		return $this->name;
	}
}

class Fruit extends Food {
	function getName(){
		return $this->name." (fruit)";
	}
}

$fruit = new Fruit("Cherry");

echo $fruit->getName();   # displays Cherry (fruit)

echo Fruit::getDefinition();   # displays Food is nourishment for carbon-based lifeforms.

?>

Things to notice:

  • All methods in a class must be preceded by the function keyword.
  • Static methods require the static keyword
  • Instance methods can refer to the current instance through the implicit variable $this
  • To access properties and methods from an instance, use an arrow: $instance->property
  • To access static properties and methods from a class, use two colons: ClassName::StaticPropertyOrMethod
  • Instances of classes are defined using the syntax $instance = new ClassName(); like in Java

Outputting Data

What's the point of a web language if we can't output data? The most basic method for outputting data is using either the echo or print statement:

<?php
echo "Hello World";   # outputs Hello World to the browser
?>

You often find yourself wanting to print all information associated with a variable for debugging purposes. PHP provides the handy var_dump function for that:

<?php
var_dump($myvar);
?>

sprintf()

Code in PHP that outputs information can get very ugly. Consider, for example, the following snippet:

<?php
$medals = array(
	"United States" => array(46, 29, 29),
	"China" => array(38, 27, 23),
	"Russia" => array(24, 26, 32)
);
?>

<table>
	<tr>
		<th>Country</th>
		<th>Gold Medals</th>
		<th>Silver Medals</th>
		<th>Bronze Medals</th>
	</tr>
<?php
foreach($medals as $country => $counts){
	echo "\t<tr>\n\t\t<td>".htmlentities($country)."</td>\n\t\t<td>".htmlentities($counts[0])."</td>\n\t\t<td>".htmlentities($counts[1])."</td>\n\t\t<td>".htmlentities($counts[2])."</td>\n\t</tr>\n";
}
?>
</table>

This code will generate the following HTML:

<table>
	<tr>
		<th>Country</th>
		<th>Gold Medals</th>
		<th>Silver Medals</th>
		<th>Bronze Medals</th>
	</tr>
	<tr>
		<td>United States</td>
		<td>46</td>
		<td>29</td>
		<td>29</td>
	</tr>
	<tr>
		<td>China</td>
		<td>38</td>
		<td>27</td>
		<td>23</td>
	</tr>
	<tr>
		<td>Russia</td>
		<td>24</td>
		<td>26</td>
		<td>32</td>
	</tr>
</table>

It's not very clear, though, that this is what the PHP code is going to generate. In particular, the echo line inside the foreach loop is 196 jumbled characters!

sprintf() is a nifty PHP function (with roots in C) that allows us to clean up that code. We get the same output as above if we use the following PHP instead:

<?php
$medals = array(
	"United States" => array(46, 29, 29),
	"China" => array(38, 27, 23),
	"Russia" => array(24, 26, 32)
);
?>

<table>
	<tr>
		<th>Country</th>
		<th>Gold Medals</th>
		<th>Silver Medals</th>
		<th>Bronze Medals</th>
	</tr>
<?php
foreach($medals as $country => $counts){
	echo sprintf("\t<tr>\n\t\t<td>%s</td>\n\t\t<td>%d</td>\n\t\t<td>%d</td>\n\t\t<td>%d</td>\n\t</tr>\n",
		htmlentities($country),
		$counts[0],
		$counts[1],
		$counts[2]
	);
}
?>
</table>

The above code is more straightforward and self-explanatory than the first example, and it is also easier to edit and maintain.

Here's how sprintf() works. The first argument is a format string. A format string can contain conversion specifications for additional data that will be inserted into the format string. The most common conversion specifications are:

  • %s for a string
  • %d for a signed integer
  • %u for an unsigned integer
  • %f for a floating-point number
    • %.2f for a floating-point number with 2 decimal places
  • %% for a literal percentage sign

For more detail on sprintf formats, refer to the PHP documentation.

The remaining arguments are the data that are inserted into each of the conversion specifications. In the example above, there are four conversion specifications ('%s, %d, %d, and %d), so sprintf() takes 4 additional arguments after the format string.

Note that we still need to sanitize string output (using htmlentities() ) when we are using sprintf(). However, since our format string specifies integers for the remaining three arguments, sprintf() will take care of type casting, so we no longer need to worry about sanitizing the integers.

An additional tip: printf() is a shortcut for echo sprintf(). That is, the following lines are functionally equivalent:

<?php
$n = 12345.678;
printf("%.2f\n", $n); // prints 12345.68
echo sprintf("%.2f\n", $n); // also prints 12345.68
?>

Passing Variables

Input values can be passed to a script either through the URL request line or through data submitted by a form. Built in arrays $_GET['var'] and $_POST['var'] return the value of var depending on the access method. As we will see in the next section, values can also be passed through session variables. Finally, you can use cookies to store and retrieve values.

Note that upon submitting a form, the page specified in the form tag's action attribute is loaded (with variables sent via post or get).

GET: Passing Variables via URL

If you want to pass values in a URL, the format is ''http://example.com/yourphpfile.php?var1=value1&var2=value2.....''

PHP saves URL variables in the associative array $_GET.

For example, the following PHP document would print a hello message according to a name given in the URL.

<!DOCTYPE html>
<head><title>Hello World</title></head>
<body>
<?php
$name = $_GET['name'];

printf("<p>Hello, %s; how do you do?</p>\n",
	htmlentities($name)
);
?>
</body>
</html>

If you access the URL like this: greeting.php?name=Alice, it will show Hello, %s; how do you do?

POST: Passing Variables via Form

Another method for passing variables from page to page is by sending it via POST variables. Like with GET, POST variables are saved in an associative array, this time named $_POST.

Consider the following form:

<!DOCTYPE html>
<head><title>Hello World</title></head>
<body>
<form action="info.php" method="POST">
	<p>
		<label for="firstnameinput">First Name:</label>
		<input type="text" name="firstname" id="firstnameinput" />
	</p>
	<p>
		<label for="lastnameinput">Last Name:</label>
		<input type="text" name="lastname" id="lastnameinput" />
	</p>
	<p>
		<label for="birthyearinput">Birth Year:</label>
		<input type="number" name="birthyear" id="birthyearinput" />
	</p>
	<p>
		<strong>Gender:</strong>
		<input type="number" name="gender" value="male" id="maleinput" /> <label for="maleinput">Male</label> &nbsp;
		<input type="number" name="gender" value="female" id="femaleinput" /> <label for="femaleinput">Female</label>
	</p>
	<p>
		<input type="submit" value="Send" />
		<input type="reset" />
	</p>
</form>
</body>
</html>

For more information on the HTML markup in the above example, refer to the HTML and CSS guide.

This submits a form with POST data to info.php. Inside info.php, the provided values will be available in the associative $_POST array under the keys firstname, lastname, birthyear, and gender.

To display the submitted input on a target page, info.php could contain:

<!DOCTYPE html>
<head><title>Person Information</title></head>
<body>
<?php
$first = $_POST['firstname'];
$last = $_POST['lastname'];
$birthyear = (int) $_POST['birthyear'];
$gender = $_POST['gender'];
$age = 2012 - $birthyear;

printf("<p>Hello, %s %s!  You were born in %d, so you are %d years old.  You are %d.</p>\n",
	htmlentities($first),
	htmlentities($last),
	$birthyear,
	$age,
	htmlentities($gender)
);
?>
</body>
</html>

Note: It is very important that you always sanitize strings that you output to the browser using htmlentities() or a similar function. If you don't, your site will be vulnerable to all sorts of malware. For more information, refer to the Web Application Security guide.

For further help with using HTML forms with PHP, we recommend this tutorial.

Self-Submitting Forms

Oftentimes we don't want to pass form values to a different page, but rather to the same page as contains the form so that we can process the information and display output on that same page. To do this, you can simply omit the action parameter from the form. Alternatively, you can use a PHP environment variable like $_SERVER['PHP_SELF'].

The following example simply takes the data input from a form and, via POST variables, echoes it back to the user as bold text on the same page:

<!DOCTYPE html>
<html>
<head><title>Bold Printer</title></head>
<body>
<form action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" method="POST">
	<p>
		<label for="name">Name:</label>
		<input type="text" name="name" id="name" />
	</p>
	<p>
		<input type="submit" value="Print in Bold" />
	</p>
</form>

<?php
if(isset($_POST['name'])){
	printf("<p><strong>%s</strong></p>\n",
		htmlentities($_POST['name'])
	);
}
?>
</body>
</html>

Sessions

If you need to keep track of information associated with a user between page loads, you should use a session. Sessions are excellent for keeping track of the currently-logged-in user, for example.

PHP makes session management dirt simple. Whenever you need to use session variables, simply call session_start(). Then, you may interact with the $_SESSION associative array, and PHP will take care of accessing and saving all session variables for you!

For example, the following page will display a number, and then double that number on each page reload:

<?php
session_start();

$oldnum = (int) $_SESSION['inc_num'] || 0;
$newnum = $oldnum*2;

echo $newnum;
$_SESSION['inc_num'] = $newnum;
?>

Sessions also work across different pages, as long as they are on the same web server.

Other PHP Tips

Redirecting to a Different Page

If you want to redirect the user to a different page, you need to send a Location header. For example, a page containing only this code would redirect the user to the login.php file:

<?php
header("Location: login.php");
exit;   // we call exit here so that the script will stop executing before the connection is broken
?>

It is often useful to perform redirects after you perform server-side operations.

Important: You should generally not leave a user sitting on a page that has POST data, because if they refresh the page, their POST data will be submitted again, causing your server to perform an action twice. Rather, you should perform the operation, and then redirect them to another page that does not contain POST data in the header.

Reading a File Line-by-Line

If you want to read a file line-by-line, open a file handler using fopen(), use fgets() to read lines until you've reached the end, and then close the file using fclose().

The following example reads file_with_lines.txt and outputs its content in an unordered list, where each list item is a line in the file:

<?php
$h = fopen("file_with_lines.txt", "r");

$linenum = 1;
echo "<ul>\n";
while( !feof($h) ){
	printf("\t<li>Line %d: %s</li>\n",
		$linenum++,
		fgets($h)
	);
}
echo "</ul>\n";

fclose($h);
?>

Note: If you want to read an entire file, PHP provides the file_get_contents() function, which is basically a shortcut for fopen(), fread(), and fclose().

Sending a File to the Browser

Another useful function to know is the readfile function. It takes a file on the webserver's file system and sends it to the web browser. A simple example is given below, but note that you'll probably need to specify addition header fields in order to have the web browser download the file correctly.

The following example loads a file associated with a certain username and displays it.

<?php
session_start();

$filename = $_GET['file'];

// We need to make sure that the filename is in a valid format; if it's not, display an error and leave the script.
// To perform the check, we will use a regular expression.
if( !preg_match('/^[\w_\.\-]+$/', $filename) ){
	echo "Invalid filename";
	exit;
}

// Get the username and make sure that it is alphanumeric with limited other characters.
// You shouldn't allow usernames with unusual characters anyway, but it's always best to perform a sanity check
// since we will be concatenating the string to load files from the filesystem.
$username = $_SESSION['username'];
if( !preg_match('/^[\w_\-]+$/', $username) ){
	echo "Invalid username";
	exit;
}

$full_path = sprintf("/srv/uploads/%s/%s", $username, $filename);

// Now we need to get the MIME type (e.g., image/jpeg).  PHP provides a neat little interface to do this called finfo.
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($full_path);

// Finally, set the Content-Type header to the MIME type of the file, and display the file.
header("Content-Type: ".$mime);
readfile($full_path);

?>

Uploading a File

Uploading files is similar to submitting data in forms. For starters, you need a form that submits to your uploading script:

<form enctype="multipart/form-data" action="uploader.php" method="POST">
	<p>
		<input type="hidden" name="MAX_FILE_SIZE" value="20000000" />
		<label for="uploadfile_input">Choose a file to upload:</label> <input name="uploadedfile" type="file" id="uploadfile_input" />
	</p>
	<p>
		<input type="submit" value="Upload File" />
	</p>
</form>

Note that we need to specify enctype="multipart/form-data" on the form. This is to enable files to be uploaded and recognized by PHP.

PHP puts all files submitted with a form into the $_FILES superglobal array. Each entry in the $_FILES array contains the following information:

  • $_FILES['uploadedfile']['name'] is the original name of the file on the client's machine
  • $_FILES['uploadedfile']['type'] is the MIME type of the file according to the browser (don't take it for granted)
  • $_FILES['uploadedfile']['size'] is the size, in bytes, of the uploaded file
  • $_FILES['uploadedfile']['tmp_name'] is the temporary location on your filesystem where Apache saved the uploaded file
  • $_FILES['uploadedfile']['error'] is the error code associated with the file upload (if applicable)

To upload the file submitted by the form above in a user's special folder, we could use the following PHP code:

<?php
session_start();

// Get the filename and make sure it is valid
$filename = basename($_FILES['uploadedfile']['name']);
if( !preg_match('/^[\w_\.\-]+$/', $filename) ){
	echo "Invalid filename";
	exit;
}

// Get the username and make sure it is valid
$username = $_SESSION['username'];
if( !preg_match('/^[\w_\-]+$/', $username) ){
	echo "Invalid username";
	exit;
}

$full_path = sprintf("/srv/uploads/%s/%s", $username, $filename);

if( move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $full_path) ){
	header("Location: upload_success.html");
	exit;
}else{
	header("Location: upload_failure.html");
	exit;
}

?>

Note: A lot of the code above is the same as the code in the file download example. In your project, you should save the logic of generating the file path (in a function) in a third file that you include into the upload and download scripts.

Note: By default, PHP will not allow a file upload of more than 2 MB. SitePoint has an excellent tutorial for how to increase this limit: http://www.sitepoint.com/upload-large-files-in-php/

PHP Reference

If you ever have a question about PHP, first check the well-written documentation. To skip immediately to the documentation on any function, simply visit http://php.net/functionname. For example: http://php.net/var_dump