Misc PHP Info

Learning PHP

PHP the Right Way is a great resource when first getting started with PHP.

The best book I've found for learning PHP, and other things, is Learning PHP, MySQL, JavaScript, & CSS by Robin Nixon. The table of contents pages are here. The sample code is here. Chapter 16 is especially good for Form processing.

Configuration for Development

Settings

 

Handling Notices

Instead of using falsy logic, it is better to explicitly check to see if a variable is first set. Otherwise, PHP will generate a Notice error. This can be fixed as follows:

if (isset($_GET['barrier'])) {
	if ($_GET['barrier']==='closed') {
		echo 'alert("Access to that course has been suspended.");' . PHP_EOL;
	}
}

Alternatively, using the array_key_exists() function may work better. As in:

array_key_exists('barrier',$_GET)

Classes and functions()

Function Arguments

Normally, when you pass a variable into a function, it is done “by value”. If you want to pass a variable “by reference”, then prefix the variable name with an ampersand.

function titleCase(&$name, $isAwesome = false) {
	$name = ucfirst(strtolower($name));
	if ($isAwesome) {
		$name .= ' is awesome!';
}
$myName = "CrAiG";
titleCase($myName);
echo $myName; //Craig

titleCase($myName, true);
echo $myName; //Craig is awesome!

Creating an Empty Object

To create an empty object (similar to what Javascript does with myObject = {};), you can use:

$myObject = new stdClass();

or

$myObject = (object) null;

Creating an Empty Array

$myArray = array();

To add items to the end of the array leave the array index blank, for example:

$myArray[] = $newItem;

Forms

To call the same page that the form is on, use this action attribute.

<form action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>" method="POST">

Passing Data

To pass data (via GET variables) the function http_build_query($queryData) may come in handy. For example:

$myGetVariables['pageId'] = 14;
$myGetVariables['action'] = 'rebuild';
header('Location: mypage.php?' . http_build_query($myGetVariables));

Which results in the url mypage.php?pageId=14&action=rebuild

Headers

You will often find the need to call one PHP page, but return a different one. PHP’s equivalent of the HTML statement
document.location = "http://www.myDomain.com"; /* Javascript */ is
header('Location: http://www.myDomain.com'); /* PHP code */

PHP’s header function will only accept a fully qualified filename, but you can mimic relative paths using this code:

$host  = $_SERVER['HTTP_HOST']; //domain name (no trailing slash)
$uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\'); //folder containing this page (no trailing slash)

//modify the $uri to go up one level
$uriArray = explode("/",$uri);
unset($uriArray[count($uriArray) - 1]); //remove the last item in the array (i.e. go up one level)
$uri = implode("/",$uriArray); //reassemble the string

$extra = 'myNewPage.php';

header("Location: http://$host$uri/$extra");

Echo

There are a few ways to write code out to your web page. The first is a single line echo like:

$variable = 'cats';
echo "<p>I enjoy $variable.</p>"; //I enjoy cats.

Because the previous line uses double quotes, variable names will be replaced with their contents. Using a single quote would result in: I enjoy $variable.

heredoc Syntax

In the previous example, variables can be resolved or not, depending on the use of double or single quotes. The same is true when defining Strings using heredoc and nowdoc syntax.

<?php
$variable = 'cats';
echo <<<END
<div>
	<h1>My Header</h1>
	<p>I enjoy $variable.</p> //resolves the variable
</div>
END;
?>

The previous block of code will resolve the variable, whereas the next will not.

nowdoc Syntax

The difference is the single quotes around the word END. You can use any word after the <<<, just make sure you use the same word to mark the end of your block. The ending marker must also start in the first column and can be the only thing on that line.

<?php
$variable = 'cats';
echo <<<'END'
<div>
	<h1>My Header</h1>
	<p>I enjoy $variable.</p> //will not resolve the variable
</div>
END;
?>

Another Option

If you are conditionally echoing a large chunk of HTML, then this syntax will probably be easier to use.

<?php if ($lovesCakes): ?>
<div>
	<h1>Pancake Master</h1>
	<p>I enjoy making pancakes.</p>
</div>
<?php endif; ?>

In this example I used PHP’s Alternative Syntax for Control Structures. You could also use the standard curly brace syntax. Many people feel the code is easy to read the Alternative Syntax when mixing PHP and other languages (HTML, CSS, Javascript, etc.).

Includes

Let’s say your directory structure looks like this:

Specifying the location of your include files can get a bit tricky because the location of the file is relative to the page called by the browser. Certainly not a problem if page A includes page B; but when A includes B, and B includes C, and C includes B, and all these files are in different directories; well then you'll have references to files that can not be resolved. This strategy works pretty well to make sense of it all.

1. Organize your directory structure.

Arrange your files such that browser-facing files (such as index.php) are anywhere except the “includes” directory. The files inside “includes” should never be called from the browser address bar.

2. Create some PHP constants that define the location of the “include” folder.

common.php will contain the magic bit of code that tells other other files where to find the includes. This would also be a great place to put your database connection information. Note to self: See the GEM project for an example.

//dirname(__FILE__)); //get the directory location of this included file
define('APP_ROOT', dirname(dirname(__FILE__))); //double-pumping to go up one level since this is in a sub-directory.
define('INCLUDE_ROOT', APP_ROOT . "/php/");

3. Use the common.php file.

Our new constants (APP_ROOT and INCLUDE_ROOT) won’t do any good unless you get them into your web pages; therefore, all files that need an include will first need a hard-coded reference to common.php. This applies to both browser-facing files such as index.php and files called via AJAX such as actions/insertRecord.php.

Example: In index.php you would have:

<?php
require_once 'includes/common.php';

//Build the page structure
require_once INCLUDE_ROOT . 'htmlFragments/header.php';
require_once INCLUDE_ROOT . 'htmlFragments/main.php';
require_once INCLUDE_ROOT . 'htmlFragments/footer.php';

?>

Notice that once common.php has been loaded, you can start to use the constant INCLUDE_ROOT. All “require” and “include” statements use INCLUDE_ROOT.

Let’s say studentRecords.php uses an instance of the Student class, defined in student.php, and it calls a method in course.php.

studentRecords.php is:

<?php
require_once 'includes/common.php';
require_once INCLUDE_ROOT . 'classes/Student.php';

//Build the page structure
require_once INCLUDE_ROOT . 'htmlFragments/header.php';
require_once INCLUDE_ROOT . 'htmlFragments/main.php';

$s = new Student("Craig");
$s->showCourses();

require_once INCLUDE_ROOT . 'htmlFragments/footer.php';

?>

Student.php would start out like this:

<?php
require_once INCLUDE_ROOT . 'classes/course.php';

class Student {
	public function showCourses() {
		$courseArray = Course::getCourses($this->studentId);
		//echo out the list of courses for this student
	}
}
?>

The require_once will work because INCLUDE_ROOT was already brought in by studentRecords.php. This is why it is vital that no file inside the “includes” directory are ever called directly.

Variables and Constants

Variables are defined simply by referencing them. All variable must begin with a $ character. Ex: $myVar = 1;

To reference a variable variable name, enclose it in curly braces. e.g. $pr->{'response'.($idx + 1)} = $guess; Here I am setting an instance variable (for example, $pr->response1, $pr->response2, $pr->response3, etc.) value to $guess.

Constants are defined with the PHP function define(). Ex: define("MY_CONSTANT", 3.14159); By convention, constants are usually in all upper-case. To use your constant, just reference its name. i.e. $pi = MY_CONSTANT;

Pre-defined “Magic” Constants

PHP comes with some constants already for you to use (they are prefixed and suffixed with double underscores):

__LINE__ : The current line number of the file.

__FILE__ : The full path and filename of the file. If inside an include, then the include's filename is used.

__DIR__ : Directory of the file.

__FUNCTION__ : The function's name

__CLASS__ : The class name.

__METHOD__ : The class method name.

__NAMESPACE__ : The current namespace.

Variable Scope

Variables are visible only within the area in which they are defined. If you would like a global variable to be visible to a function, then use the global keyword as in the following example.

$db = new PDO($dbDSN, $dbUserId, $dbPassword);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

function showDbInfo() {
 	global $db;
	echo $db->getAttribute(PDO::ATTR_CONNECTION_STATUS);
}
showDbInfo();

Handling Dates with PHP and MySQL

This section has not been written yet. I have some notes in my green folder and an example is in the Intel Solution Architect 2013 project. See claimform/index.php.

Information from Richard Lord’s blog post (click here to view)

Dates in PHP and MySQL

PHP uses unix timestamps for all its date functionality. It has methods to convert these timestamps into pretty much any text format you could want but internally it uses the timestamp format. A timestamp is simply an integer. Specifically, it's the number of seconds that have elapsed since midnight on January 1st 1970 (greenwich mean time).

MySQL has three date types for use in columns. These are DATETIME, DATE, and TIMESTAMP. DATETIME columns store date and time as a string in the form YYYY-MM-DD HH:MM:SS (e.g. 2006-12-25 13:43:15). DATE columns use just the date part of this format – YYYY-MM-DD (e.g. 2006-12-25). TIMESTAMP columns, despite their name, are nothing like the unix timestamps used in PHP. A TIMESTAMP column is simply a DATETIME column that automatically updates to the current time every time the contents of that record are altered. (That's a simplification but broadly true and the details are not important here). In particular, since version 4.1 of MySQL the TIMESTAMP format is exactly the same as the DATETIME format.

So the problem is how to work with these two very different date formats – the PHP timestamp integer and the MySQL DATETIME string. There are three common solutions…

One common solution is to store the dates in DATETIME fields and use PHPs date() and strtotime() functions to convert between PHP timestamps and MySQL DATETIMEs. The methods would be used as follows -

$mysqldate = date( 'Y-m-d H:i:s', $phpdate );
 			$phpdate = strtotime( $mysqldate );

Our second option is to let MySQL do the work. MySQL has functions we can use to convert the data at the point where we access the database. UNIX_TIMESTAMP will convert from DATETIME to PHP timestamp and FROM_UNIXTIME will convert from PHP timestamp to DATETIME. The methods are used within the SQL query. So we insert and update dates using queries like this -

$query = "UPDATE table SET
 			datetimefield = FROM_UNIXTIME($phpdate)
 			WHERE...";
 			$query = "SELECT UNIX_TIMESTAMP(datetimefield)
 			FROM table WHERE...";

Our last option is simply to use the PHP timestamp format everywhere. Since a PHP timestamp is a signed integer, use an integer field in MySQL to store the timestamp in. This way there's no conversion and we can just move PHP timestamps into and out of the database without any issues at all.

Be aware, however, that by using an integer field to store your dates you lose a lot of functionality within MySQL because MySQL doesn't know that your dates are dates. You can still sort records on your date fields since php timestamps increase regularly over time, but if you want to use any of MySQL's date and time functions on the data then you'll need to use FROM_UNIXTIME to get a MySQL DATETIME for the function to work on.

However, if you're just using the database to store the date information and any manipulation of it will take place in PHP then there's no problems.

So finally we come to the choice of which to use. For me, if you don't need to manipulate the dates within MySQL then there's no contest and the last option is the best. It's simple to use and is the most efficient in terms of storage space in the data table and speed of execution when reading and writing the data.

However, some queries will be more complicated because your date is not in a date field (e.g. select all users who's birthday is today) and you may lose out in the long run. If this is the case it may be better to use either option 1 or 2. Which of these you use depends on whether you'd rather place the work on MySQL or PHP. I tend to use option 2 but there's no right or wrong answer – take your pick.

So to summarise, for those who've skipped straight to the last paragraph, most of the time I use option 3 but occasionally I use option 2 because I need MySQL to know the field contains a date.

 

phpinfo()

The phpinfo() function returns data about your PHP installation. This function will generate a complete, fully-formed web page, so start with a blank file, name it something like "info.php" and put this in it:

<?php
	phpinfo();
?>

Security

OWASP Zed Attack Proxy can be used to test the security vulnerabilities of your web app.

Survive the Deep End: PHP Security is a great resource for learning how to secure your site.