Programming in PHP


1 - * - Introduction to PHP

  1.1 - * - Learning to program in Perl or PHP

  1.2 - * - Remember a site's non-technical issues too

  1.3 - * - Testing you Perl / PHP / MySQL / Tcl knowledge

  1.4 - * - PHP Course - for hobby / club / charity users.

  1.5 - * - Programming languages - a comparison

2 - * - A First Web Page

  2.1 - * - It's REALLY easy to add a little PHP

  2.2 - * - Using print_r in PHP to explore mysql database requests

3 - * - Variables, operators and expressions

  3.1 - * - Getting rid of variables after you have finished with them

  3.2 - * - If nothing, make it nothing.

  3.3 - * - Double Dollars in PHP

4 - * - Control Statements

  4.1 - * - Decisions - small ones, or big ones?

  4.2 - * - Don't repeat code - use loops or functions

  4.3 - * - Testing for one of a list of values.

  4.4 - * - Assignment, equality and identity in PHP

5 - * - Designing PHP Solutions - best practise

  5.1 - * - How to build a test harness into your PHP

  5.2 - * - Not just a PHP program - a good web application

  5.3 - * - Adding a newsfeed for your users to a multipage PHP application

  5.4 - * - Improving the structure of your early PHP programs


Manual Origin and Copyright Statement

Notice of Rights

All rights reserved. No part of this manual, including interior design, may be reproduced or translated into any language in any form, or transmitted in any form or by any means electronic, mechanical, photocopying, recording or otherwise, without prior written permission of Well House Consultants except in the case of brief quotations embodied in critical articles and reviews. For more information on getting permission for reprints and excerpts, contact Graham Ellis at Well House Consultants.

This manual is subject to the condition that it shall not, by way of trade or otherwise, be lent, sold, hired out or otherwise circulated without the publisher's prior consent, incomplete nor in any form of binding or cover other than in which it is published and without a similar condition including this condition being imposed on the subsequent receiver.

Notice of Liability

ll brand names and product names used in this book are trade names, service marks, trademarks or registered trademarks of their respective owners. Well House Consultants is not associated with any product or vendor in this book and where such designations appear in this book, and Well House Consultants was aware of a trademark claim, the designations have been appropriately capitalised. Well House Consultants cannot attest to the accuracy of this information and use of a term should not be regarded as affecting the validity of any trademark or service mark.

The information in this book is distributed on an "as is" basis, without warranty. Whilst every precaution has been taken in the preparation of this manual, neither the author nor Well House Consultants assumes responsibility for errors or omissions, nor shall be liable to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the instructions contained in this book or by the computer software and hardware products described herein.

1 Introduction to PHP

[top] - [resources] - [index]

1.1 - Learning to program in Perl or PHP - [577]

* Course - Perl for Beginners.
* Tutor lead lessons - Learning to Program in PHP.
* Classes in MySQL from the ground up.

Our IT industry can be so inward-looking at times! Many training courses are really conversion courses where a programmer skilled in language P learns language Q. Such courses are certainly a product for which there's a market need, but there's also the need for a different product - "Learning to ..." courses.

I was on a cruise to Alaska with Larry Wall (the guy who wrote Perl) together with a bunch of around 100 other enthusiastic practitioners, and someone asked Larry if he would recommend Perl as a first language. "Sure, why not" was his reply. Mind you, taking a survey of the group, most of them had started with something else. So ...

There's a lot of very bright people out there who are "computer=savyy" or "net-aware" but have never programmed or designed a database in their lives. Quite simply, they've had too much else to do from blowing glass to offering legal advice, to reporting for the local paper. But something brings them to PHP or to MySQL. The need for a specialist statistical analysis of some data perhaps, or a requirement to make information interactively available through a web site. And it's very hard to find an absolute beginner's course for such people.

Personally, I love running some of our more fundamental courses. To see the real and very effective results - and pleasure too - that people get from what is rarely rocket science. A joy, and a customer's requirement well met. I appreciate that many tutors feel that the more fundamental stuff is beneath them, or assume that their class knows these things; that's fair enough on a course that's labelled "intermediate" or "advanced".

If you're learning Perl, or PHP or MySQL or Tcl from scratch, we can help you with a training course - (matrix). If you're learning Python or Ruby from scratch, we can probably help too; please email me and let me know a little bit about what you're looking for.

1.2 - Remember a site's non-technical issues too - [795]

From the PHP course yesterday ... we came up with a list of extra considerations (beyond the narrow technical) for your PHP Web applications. Thought you might like to share the checklist ...

Search Engine Optimisation

Good URLs
Good Original Content
Links from / to other good sites
Clear HTML
Code to help search engines
Regular site updates
Using keywords
Providing ALT tags on images
Provide a robots.txt file

Commercial Matters

Do you WANT this data found?
Competitors
Moving old data out the way
Security
Domain Protection

Legal

Disability Discrimitation Act
Copyright
Libel
Decency
Racial hatred, incitement, etc
Privacy
Data Protection
Acceptable User Policy

1.3 - Testing you Perl / PHP / MySQL / Tcl knowledge - [691]

There are some aspects of our work - such as training and helping people specify and plan their systems - that have a positive aura about them and are naturally forward looking. Yes, we celebrate those jobs.

Other aspects, such as support and repair work, start off with a natural "down" - we're called in because of a problem, but chances are of a positive outcome in the end once we get the thing fixed or suggest ways forward. Again, great work if a bit of a gamble on the outcome - some things that people want to do just ain't practical or within their knowledge, they're unwilling to put time and perhaps money aside to learn, and they go away disappointed.

When we put up our on line quizzes way back in 2001, we didn't look at them as anything particularly different - a nice way to help potential training delegates find out what level of course was best for them, or if they knew most of it anyway and could save themselves the money. Well - that was the idea.

Alas, if a user gets 12 our of 15 questions on a quiz right, he will often look at the three he got wrong in great detail. Perhaps he'll feel cheated if the question can be mis-read in any way, or if there are any shades of grey at all in the answer. So the quizzes become quite high maintenance with us having to explain and justify questions rather more often than I would like ...

We have seriously discussed "pulling" the quizzes - and it may happen at some stage - but I do see them used by about a dozen people a day. I've upgraded the look and feel of all four quizzes this morning, I've added a reminder at the top of each of them that questions get dated and we would appreciate updates, and I've given them what is - I hope - a new lease of life.

Please try out the quizzes ...
PHP Quiz
Perl Quiz
Tcl Tk and Expect Quiz
MySQL Quiz
and the quiz index and FAQ is here

Please email me - graham@wellho.net if you spot anything that's ambiguous or out of date (or plain wrong!)

Oh - and do YOU have any good questions you think I should add? Please let me know

1.4 - PHP Course - for hobby / club / charity users. - [2097]

Are you looking after a PHP based web site but want to do more with it? Perhaps it's the web site for your cricket club, your local school, or a charity or special interest group you work with?

What is this course all about?

Traditionally, our courses have run during the week and been aimed at commercial organisations - smaller groups of delegates, intensive courses to get the employees of those companies - for whom time is money - quickly and well trained during work hours. But more and more requests are coming our way for something that's more suited for the enthusiast / hobby end of the market. So we're running - as an experiment initially - a PHP techniques weekend. Here are the 'bullets':
• The course will be residential at our Melksham, Wiltshire training centre and hotel.
• It is aimed at those with some (not necessarily a lot) of PHP experience
• The objective of the two days is to ensure that you'll have a great learning weekend and leave able to do a lot more of what you want to do
• you'll be able to get back with the tutor - and perhaps with your fellow delegates - after the course with follow up questions
• and you'll have fun!

(If you have no prior PHP knowledge, this particular weekend isn't the one for you - please email me - graham@wellho.net)

This is an example that we'll have available during the course - showing current issues with train service (lines) and on the roads (spots) in the South West of England. It's a dynamic diagram so it may just be an outline - or it may be covered on data to indicate serious transport problems! See here for a detailed key.

When is the course and how does it run?

The course will be run by Well House Consultants who run a full training program in Open Source programming at their Well House Manor training centre in Melksham, Wiltshire where clients include many of the top uk companies, educational establishments and government bodies. The same equipment and training rooms will be used for this course, which will be lead by Graham Ellis who is the author of the material and Director of Well House.

Arrive on the evening of Friday, 22nd May 2009.

Settle in / get online / get set up using the course web server that will run your code, and get to know your fellow delegates.

Saturday, 23rd May

We'll start the day after an early breakfast with a review of PHP - a dash through the basics to help you pick up on any little missing holes in your knowledge, and to help you qualify your code so that you'll start looking at easy of writing and maintainance, and code security, as the future bedrock of your coding. Those might be low down your priority list at the moment, but they'll become critical on a popular site.

Linking a series of visits by the same user together into a session is a critical part of many web applications, and after coffee we'll look at sessions, and how to write good session code - you may have heard terms like "4 layer model" and MVC and we'll see how those design approaches can be applied, together with worked examples.

Lunch will be provided.


In the afternoon, we'll look at some specific subjects, with practical sessions and assistance based on our library of modules. Each delegate will be invited to broach a subject before these sessions begin, and we'll cover topics relevant to everyone. Here's a taster of some of the subjects on offer:

* Optimising your dynamic pages for the search engines such as Google
* Finding resources - already written code, modules, and answers
* Naughty Word Filtering, Spell Checking, suggesting similar words
* Checking your user is real (answer a question, type text from a graphic)
* Data Validation / making your site easy to use / Avoiding bloopers
* Getting users to sign in and maintaining user accounts. "Forgot my password"
* Credit card and other secure payment issues
* Linking web data to and from your other (nonweb) databases
* Consistent look and feel and flexibility - using CSS with PHP
* Cutting in feeds from other sites - RSS, SOAP and other options
* Identifying where in the world your visitor is coming from
* Did your visitor arrive via a search engine? What are they looking for?
* Making use of mapping resources such as Google on your site
* Providing User Feedback screens
* Writing for a wide variety of browsers
* Should we be using Flash / Ajax / Javascript?
* Should I use PHP objects?
* Producing dynamic maps, diagrams and graphs through PHP
* Sorting results by location
* Site searches - how to produce helpful results
* Caching and other loading issues
* Selecting your web space provider, and running your own server
* This list in not exhaustive - bring your code and questions

We'll run into the early evening - the training room will be accessible to you as late as you like, and the tutor around until mid evening if required.

Sunday, 24th May

After breakfast, a more formal session will look at the wider responsibility of running a web site - issues from copyright to data protection and privacy, and from usability through security, and from Disability Discrimination to Acceptable User and moderation policies. These may not be 'PHP Programming' subjects, but they are just as important for you to have a legal and successful web site.

After Coffee, we'll spend time on how to write secure, reusable code and how to deal with all manner of security issues. "Do I really need this for my little site that's concerned with the Netherhampton Rugby Club" you may ask. Yes, you do; if you leave an opening, you could find an application at www.netherhamptonrugbyclub.org.uk that you've forgotten about has become a hotbed of porn (I've been there!)

Late morning, and afternoon (lunch provided once again), we'll be back to the list of topics that was drawn up on Saturday.

Late afternoon, and a concluding summary ... and you can be on your way. You'll go away with a lot more knowledge of PHP - and a wider knowledge as to how it can be applied to your site. You'll go away with ideas, and with links and materials through which you can practically follow them up. And you'll leave with a support route and contacts with and through whom you can raise further issues.

Delegates are welcome to stay on Sunday evening and into Monday morning - Monday is a bank holiday, and there's a great deal to see in Wiltshire!

Pricing

For this weekend course, we are offering the following special prices:

Hotel Rooms: £80.00 per night (includes VAT)
Course: £100.00 per day (that's £115.00 inclusive of VAT)

So that's a total bill of £390.00, including VAT, for a 2 day residential weekend, or of £470.00 if you stay on until the Monday. Breakfast and lunch included, and there is a range of places to eat locally on Friday and Saturday evenings.

Couples or two people from the same organisation are welcome - the double / twin rate for a room is £90.00, so that's £640.00 (VAT inclusive) for 2 people on the course, or £730.00 if you stay over until Monday.

If you live in Bath, West Wiltshire, North Wiltshire, Frome or Kennett, you are welcome to book as a "day delegate" - £100.00 per day. If you live further afield then, sorry, the days are long and we recommend that you don't commute.

Please phone in or email if you want to check the suitability of this day for you, or if you want to book (01225 708225 / graham@wellho.net). 25% deposit requested with booking, rest due at the start of the course. We take cheques, Visa, MasterCard and AmEx and occasionally people have even paid in cash. You can also make an online transfer to our account ...

Second illustration - We identify our visitors by where they're visiting us from so that we can tell people to call 01144 1225 708225 from the USA, 0800 043 8225 from within the UK, and 0044 1225 708225 from elsewhere in Europe. On this map, we plot all the visitors from within the UK in the last 15 minutes, with larger dots for those of you who have visited larger numbers of pages. Other maps (see here cover Europe, and the whole world.

1.5 - Programming languages - a comparison - [317]

"It would take me a week to develop application XXX in C, 2 or 3 days in Java, and a day in Perl, PHP, or Python."

So I say when I'm teaching Perl, PHP or Python.

What do I say when I'm teaching C, C++ or Java? The same thing! But there are qualifications / differences / reasons and just because it takes much longer to develop a new application in C or Java, it doesn't mean that you shouldn't do it.

Perl, PHP and Python are all excellent languages for developing "glueware" code - and the majority of applications these days are what I describe as "glueware". That's data manipulation scripts, web server code for mining information from and updating databases, and so on and so forth.

I don't describe major system development as glueware though - for example, if I was developing a major banking system I wouldn't call it a glueware application and I might be tempted to look at a language such as Java or C++. Why, when I've already stated that Java is so much slower to develop? It's because Java is much more controllable - in other words, the encapsulation and interfacing is much more tightly defined and you can have separate developers write and test each building block, then expose only the necessary minimum of methods and code to the users of that building block. Maintenance should be easier, and code re-usabiity much higher, which goes quite some way to compensate for the extra development time. But Java code doesn't run particularly fast - so it might NOT be the answer for systems that are going to be heavily loaded.

C programs are written at a level that's much "closer" to the machine - this gives them the advantage that they're able to be very clever and to run faster - if you put the effort in - than any of the other languages that I've mentioned. And C++ builds on top of C to give a fast, close yet Object Oriented language - at the expense of some complexity and the need for a great deal of care and testing of code to ensure that you don't have "memory leaks" and the like. C remains an excellent choice for system level software and C++ for major systems and application suites that are going to be run on huge systems or in their thousands - where the cost of the slower coding can be offset against a very high utilisation in one way or another.



2 A First Web Page

[top] - [resources] - [index]

2.1 - It's REALLY easy to add a little PHP - [624]

I've taken to describing PHP and an "HTML++" language when I'm training. That's to show absolute newcomers to PHP that they can simple write a page of HTML, give it an extension such as .php, and it will function in exactly the way it always has for them.

Then, very gently, the newcomer can add in some extra tags - the "++" that I talk about in the "HTML++" of the language. These extra tags are recognised by the web server, so there's nothing at all special required by the user's browser.

I've put a demonstration of four really simple "one-liners" in PHP together to accompany this item. They are:
1. Including the date on your page (look - it's up to date)
2. Using an image that changes automatically every so often
3. Bringing in a "Message of the day" from a text file
4. Having a page include its own URL (very useful if people print the page!)

You can run the demonstration here and you'll find that I've added a fifth one-liner that lets you see the source code too - that means that you can use any of my techniques on your page. Please feel free to do so - although I would appreciate a link back to http://www.wellho.net

You may not even need to change the file extension to use PHP - if you look after your own web server, or if you're got an ISP who allows it, you may be able to add the following:
AddType application/x-httpd-php .html
to a file called .htaccess in your document directory and all pages will then have the HTML++ capabilities!


2.2 - Using print_r in PHP to explore mysql database requests - [2432]

The print_r function in PHP lets you "print raw" the contents of a variable - great for debugging and far better that print which - if you pass it an array helpfully says Array

Embed your print_r into <pre> to </pre> tags ... so that you get a good display on your browser ... otherwise you'll end up with the spaces removed and a mess. Here's an example - showing the global $_SERVER array, and also the contents of a table that's been brought back to an array of arrays:

<pre><?php
# Show server variables
print_r($_SERVER);
print ("----------------------------\n");
mysql_connect("127.0.0.1","wellho","xxxxxx");
mysql_select_db("wellho");
$rr = mysql_query("select * from recent limit 15");
print_r($rr);
print ("----------------------------\n");
$stuff = array();
while ($nextrow = mysql_fetch_assoc($rr)) {
  array_push($stuff,$nextrow); }
print_r ($stuff);
?></pre>


Select here to see what you get when you run that code. Note how the mysql_query call just returns a resource handle, and you then have to use something like mysql_fetch_assoc to get the actual data back.



3 Variables, operators and expressions

[top] - [resources] - [index]

3.1 - Getting rid of variables after you have finished with them - [748]

If you've finished with a variable in your program, you can usually just leave it "in situe" and it will be destroyed and the memory it occupied will be released when you exit from your program. In many languages, variables within named blocks of code have an even shorter "shelf life" - by default, a PHP or Python variable used within a function will be lost once you leave the function, and in Perl any variable described as a "my" variable will be lost at the end of the block in which it is declared. There *are* exceptions - if a variable reference is copied (Perl or Python) and / or if a PHP variable is declared as being static to name just a couple of examples.

But what if I've got a long-running program and I want to release the memory that a variable occupies once I've finished with it? Most languages support TWO ways of getting rid of variables:

a) You can set the variable to being empty. In this case, the variable name still exists but it contains no data, so what might previously have been a memory hog is shrunk to virtually nothing

b) You can actually remove the variable name itself from the symbol table, so that the very name ceases to exist.

If you would a metaphor - if you consider that a variable is like a cage that contains animals, then setting the variable to empty is like getting rid of the animals, and removing the variable is like destroying the whole structure of the cage.

Python

To set a variable to empty, assign None to it:
queue = None

To destroy a variable, use the del keyword:
del queue

Perl

To set a variable to empty, undef it:
undef @queue;

To destroy a variable, you may be able to use delete (but this applies only to hash members and as from Perl 5.6 to list members too:
delete $queue{"X72"};

PHP

To set a variable to empty, assign 'nothing' to it, for example:
$?queue = NULL;
or $queue = "";

To destroy a variable, use unset:
unset($queue);

Tcl, Tcl/Tk, Expect

To set a variable to empty, assign an empty string to it:
set queue ""

To destroy a variable, use unset:
unset queue

Please note that under most operating systems, memory released by emptying or destroying variables will be available for re-use by the current process, but will NOT be released back to the operating system until the process terminates. This applies to all languages, not just the ones I've highlighted in this article, as most operating systems aren't built to handle memory returned to them by shrinking processes.

3.2 - If nothing, make it nothing. - [2215]

Here's a peculiar PHP statement I wrote this morning:
  if ($aindex[$chk] == "") $aindex[$chk] = "";

What was I doing? I am actually checking to see whether there's anything in an array element and if there isn't (which could be because it's empty or because it doesn't yet exist), then it should be created if necessary and made to contain an empty string. In PHP, = = tests whether two expressions have an equal values, but = = = tests whether they are of the same type and with equal value.

The important aspect of the assignment that's made above is that it ensures that the array ends up with an element who's key is the contents of $chk, so that later on in my code I can go though all of the items using array_keys even for $chk values for which there is no data.

3.3 - Double Dollars in PHP - [483]

What does this print?

<?php
$first = "fur";
$last = "feather";
$$first = "yum yum ";
${"$first$last"} = "yikes";
print "$fur $furfeather";
?>

It prints "yum yum yikes".

In PHP, you can write a variable name within a variable name, and that's what I've done in this example.

The variable called "first" is set to contain the word "fur"
The variable who's name is in first - so that's the variable called fur - is set to "yum yum"

The variable called "last" is set to "feather"
The variable who's name is made up of the string in the variable first followed by the string in the varaible last - so that's the variable called furfeather - is set to "yikes".

This is a facility to be used sparingly - it's quite easy to write code that's unmaintainable using such structures, though they can be very useful at times for helping to generalise code.


4 Control Statements

[top] - [resources] - [index]

4.1 - Decisions - small ones, or big ones? - [1477]

When you're traveling, you'll sometimes come to a point at which you make a decision - to go one way or to go another. Sometimes the decision is a small one - for example, if I'm driving through Marlborough there's a choice of the town centre or the road around the back; whichever I take, they come back together again very quickly. And at other times the decision is much bigger - we decided to fly on our recent trip to Slovenia, and once that decision was made and we started to act on it, the whole course of our time from Sunday lunchtime through to the following Friday evening was mapped out as alternative "B" rather than "A".

All the programming languages that we teach have conditional statements - if statements, or commands - and there's a requirement in every language to define the start and end of the conditional code - where the two tracks merge again, as well as where they separate. There are a variety of ways of doing this - using insets (Python), using an endif, if or do, done pair (Shell programming) but perhaps the most common is to use curly braces. That applies in PHP and in C (today's example) and - slightly varied - in Perl and Tcl.

#include <stdio.h>
  
int main() {
  int dayslong;
  printf("How long is the course ");
  scanf("%d",&dayslong);
  
  /* Condition applies only to first printf */
  if (dayslong < 5)
    printf ("Less than a week\n");
    printf ("No weekend activities\n");
  printf ("First Job done\n");
  
  /* Condition applies to TWO printf-s */
  if (dayslong < 5) {
    printf ("Less than a week\n");
    printf ("No weekend activities\n"); }
  printf ("Second Job done\n");
}


In the first section, no curly braces are used and so the condition applies ONLY to the first printf, but in the second section with curly braces, the condition applies to the first and second printfs.

Let's run that ...

How long is the course 7
No weekend activities
First Job done
Second Job done
[trainee@daisy cd07]$ ./cb
How long is the course 4
Less than a week
No weekend activities
First Job done
Less than a week
No weekend activities
Second Job done
[trainee@daisy cd07]$

4.2 - Don't repeat code - use loops or functions - [421]

I've just answered a question about completing a whole series of radio boxes in a form, where the questioner provided sample code that had the same line, slightly modified, appearing time and time again. But if you find yourself repeating something, there must be an easier way and that way will be either a function or a loop ... the initial coding may be more complex, but when you come to expand your list of options from 5 to 15 to 50, you'll be thanking me for the advise!

I've coded an answer to the original question, written in PHP, and you can try the example here. I've included a call to the highlight_file function so that you can see the code ... and I've even commented my PHP!

4.3 - Testing for one of a list of values. - [1199]

Question [PHP] When you have a string of conditions in an 'if' clause and one side of the conditional expression is the same in each condition, is there any shortcut to avoid writing out every expression in full. For examples, rather than writing
if(($name!='Lisa')&&($name!='Leah')&&($name!='Christine')) {
can I write
if($name!=('Lisa'||'Leah'||'Christine')) {

Answer The short answer is "no - you must write it all out if you're using the != operator". In Perl 6 (different language) you WILL have a shortened syntax for this sort of thing but that's highly unusual. But lets' take a wider look at other alternatives.

In php you could write
if (!ereg ('^(Lisa|Leah|Christine)$,$name)) { ....
although that would be slighly less efficient at run time.

I do worry about hardcoding data such as people's names into a program. When Lisa decides she now wants to be called by a different name, or when Chloe joins the team, you're back to the code! Your code would be more maintainable if you had an array of names in a separate file. You could compromise with something like:
$people = array("Hermione","Bob","Sally");
if (in_array($name,$people)) { ...


Note - if you're reading your data into $name from a MySQL database, the INoperator used in a WHERE clause will allow you to filter your data before it ever reaches your PHP variables.


4.4 - Assignment, equality and identity in PHP - [406]

In PHP, you'll find that there's an = operator (that's one = sign), an == operator (that's two equals signs) and an === operator (triple equals). The single = sign is an assignment - it tells PHP to work out the expression to the right of the = sign and save it to the variable / location named on the left. Both == and === perform comparisons - so what's the difference?

== (double equals) is an equality test - it checks whether the values to the left and right of the == operator have the same value - for example, it could check if they're both the value 10. It will return a true value, though, if you compare the integer 10 to the floaring point number 10.0, or if you compare either of those to the string "10.00" ... they're all the value 10, after all!

=== (triple equals) is an identity operator which checks if the values to the left and the right of the === operator have the same value AND are of the same type, so it can only return a true value if you compare two integers or two floats or two strings ... it is bound to return a false value if you compare a float to an integer, even if they both contain the value 10.

Example:


<?php
$first = 10;
$second = 10.0;
$third = "10";

if ($first == 10) print "One";
if ($second == 10) print "Two";
if ($third == 10) print "Three";

if ($third === 10) print "Four";
if ($second === 10) print "Five";
if ($first === 10) print "Six";
?>


Will print out
OneTwoThreeSix



5 Designing PHP Solutions - best practise

[top] - [resources] - [index]

5.1 - How to build a test harness into your PHP - [2679]

I was writing a PHP demonstration yesterday, and I wanted to include a test harness with my class definitions that I could leave in place on the live code on my server, to be silently skipped over ... but which I could re-use at a later date for testing class changes, etc.

How did I do it? An environment variable, which I need to provide in order for the test harness to be run. My PHP code contains

if ($_ENV["TESTING"]) {
  # Test environment - run the file
  # On a production run this will be skipped!
  # Test code here
}


And it runs like this:

Dorothy-2:sj grahamellis$ php staticmember.php
Dorothy-2:sj grahamellis$ export TESTING=1
Dorothy-2:sj grahamellis$ php staticmember.php
Service leaves at 05:19
Service leaves at 16:39
Service leaves at 07:02
Service leaves at 17:02
The next service will have id 5
Dorothy-2:sj grahamellis$

5.2 - Not just a PHP program - a good web application - [2430]

A very busy week so far ... station pickups, a PHP course, hosting an external luncheon meeting and hotel guests at Well House Manor, and providing a venue for, and attending, a meeting of the presidents of some of the local chambers of commerce to discuss towns working together. And it's only just the end on Tuesday. Wednesday will bring ... well, you'll read some of it here.

On Monday, I "tunnelled" through PHP, producing a piece of code that worked for a benign user who put in sensible data. It coughed slightly with 'silly' values - it was obvious it had failed, and it looked really crappy - but it wasn't actually an injection attack risk. ("No - It's not nice - I will NOT publish it here"). And on Tuesday morning, I took that code and I said DESIGN MATTERS - for the user, and for the maintenance programmer ... and I came up with the following list which I chose to implement to a lesser or greater extent - at least to an illustrative degree:

1. Code should be commented for programmer
2. Page should include instructions for the user
3. Forms should include a submit button, even if they only have a single input box which submits on "enter"
4. Code should echo user inputs
5. First page should not perform submission actions on nothing
6. Fields should usually be sticky
7. Data should be validated
8. Data should be secure against injection attacks
9. Common code should be grouped into functions
10. Generated HTML should conform to selected standard (XHTML?)
11. Program and design elements should be separated
12. Error messages should be good 'uns

You see - it's not JUST about making the algorithms accessible and workable - it's much MUCH more. Come to think of it ... as I write this note, I see that there are a few more things I should have done / documented. Some have been done already - second nature - others aren't actually present in my demo.

13. Help window
14. Search Engine Optimisation
15. Make it interesting
16. Should look good and be corporate branded!
17. Should provide support contact
18. Should provide links back to the calling ap / rest of site

Have a look at the running application. Have a look at the source code. See if you can work out which of those extras I have done something towards, and which are on my potential "to do" list.

There's a huge difference between a PHP script and a good web based application!


P.S. - part built program / source [here]

5.3 - Adding a newsfeed for your users to a multipage PHP application - [2221]

As I wrote it, I realised this was turning into rather a long article, but never mind. It shows the major new components added to a "4 layer model" application I was working on the weekend before last to add in a newsfeed for logged in users to which they can contribute, together with a headlines-only display for none logged in members. The code may look longish, but it was written and tested very quickly.

If you are not familiar with the 4 layer model, start here or attend our PHP techniques workshop ... this is a more advanced article

In the particular multi page application I was modifying, page #2 is the main navigation menu, so the "finish processing stage 2" code at the top level will branch the user to many other pages in the system. Page #6 is where I added the news update:

case 2: // Navigation request made
  if ($_REQUEST[studinfo] == 1) $current = 3;
  if ($_REQUEST[studinfo] == 2) { $current = 4;
    $fill[topmsg] = "Please enter new user data"; }
  if ($_REQUEST[studinfo] == 3) $current = 6;
  if ($_REQUEST[studinfo] == 4) $xlevel = 2;
  break;


Adding data to the newsfeed is simply done by appending the data to a file, and I've checked when data is submitted that both a title and a body have been given (you'll see a comment requesting this when we come to the template form further down this example). I have used the string "::-::" as a separator / marker in the first line of each new news item in the hope that users will never add such a thing in their data ... and I'm fully aware that if I was writing something for "Joe Public" to enter data into rather that some benign and small club, this would be a bit of a hole; in such a case, I would store to a MySQL database, and within this code might have logic to delete all but the most recent 100 postings.

case 6: // Add to news feed request
  if (eregi("[a-z]",$_REQUEST[topbits]) and
    eregi("[a-z]",$_REQUEST[bottombits])) {
    $now = time();
    $fho = fopen("newsfeed.txt","a");
    fputs($fho,"$now::-::$_SESSION[username]\n");
    fputs($fho,"$_REQUEST[topbits]\n");
    fputs($fho,"$_REQUEST[bottombits]\n");
    fclose ($fho);
    }
  $current = 2;
  break;


In the 4 layer model, when you've finished handling the data submitted in the form on one page, you prepare for the next. I have added calls to a function I called newsfeed on all pages that I want to display a feed ... here is the example in the logic that prepares for a new news item, which reports a substantial amount of the old news to that the new article author can write in context. You will note that I'm putting the changing data into an array called $fill rather than generating the code directly - this is the element of the 4 layer model which allows me to separate the business logic from the look and feel - exactly what I need to do to allow for maximum future flexibility, and to allow me to pass the maintainance of code to programmers, and of the look and feel to graphic artists!

case 6: // Prepare for adding to news feed
  $fill[title] = "OurClub Adding to news feed";
  $fill[news] = newsfeed(2);
  break;


Here is the actual template ... for ease of understanding for the newcomer (i.e. to avoid ending up with a large number of files for just a demo piece) in this example, we wrote it into a "here string" ... in which we replace %-letters-% with whatever we have in the matching element of the $fill array:

$body_template[6] = <<<CLUB_TEMPLATE
<h1>Add a message to the newsfeed</h1>
Please give a headline and text of article. If you don't want to post
an article after all, just submit a blank page and it won't be added.
<form method=post>
Headline: <input name=topbits><br>
Text of article <textarea name=bottombits rows=20 cols=60></textarea><br>
When you are done ... <input type=submit></form>
<hr><b><u>The latest news feed!</u></b><br><br>%news%<br>
CLUB_TEMPLATE;


Finally, here is the 'business logic' which interprets all of the elements of the newsfeed and returns a string suitable for rendering. You'll note that even at a 'club level', I've added a number of coding / security checks - i.e. all the data the user has entered in the news goes through stripslashes and htmlspcialchars in order to render harmless any attempted injection attacks. What it does NOT do is provide any form of moderation - i.e. checking for news that breaks copyright, is libellous, adult, incites breaking of the law ... that remains a manual process.

function newsfeed($level) {
  foreach (file("newsfeed.txt") as $line) {
    $lp = explode("::-::",$line);
    if (count($lp) == 2) {
      $cur_news = $lp[0];
      $cur_repo = trim($lp[1]);
      $cur_lines = -1;
    } else {
      if ($cur_lines == -1) {
        $art_title[$cur_news] = $line;
        $art_autho[$cur_news] = $cur_repo;
        $cur_lines = 0;
      } else {
        $art_text[$cur_news] .= $line;
        $cur_lines++;
      }
    }
  } // End of feeder reader
  krsort($art_title);
  $response = "";
  $narts = 3;
  foreach (array_keys($art_title) as $tstamp) {
    $tsf = date('H:i \o\n l jS M Y',$tstamp);
    $an++;
    if ($level == 0) {
      $response = $art_title[$tstamp];
      break;
    } elseif ($level == 1) {
      $response .= "<br><b><u>$art_title[$tstamp]</u></b> by ".
        "$art_autho[$tstamp] at $tsf";
      if ($an > $narts) continue;
      $response .= "<br><br>";
      $response .= nl2br(htmlspecialchars(stripslashes("$art_text[$tstamp]")));
      if ($an > $narts * 3) break;
    } elseif ($level == 2) {
      $response .= "<br><b><u>$art_title[$tstamp]</u></b> by ".
        "$art_autho[$tstamp] at $tsf<br><br>";
      $response .= nl2br(htmlspecialchars(stripslashes("$art_text[$tstamp]")));
      if ($an > $narts * 3) break;
    }
  }
  if ($level == 1) {
    $response .= "<br><a href=\"?studinfo=4\">show more</a>";
    }
  return $response;
}



5.4 - Improving the structure of your early PHP programs - [2199]

When you first coded in PHP, you probably wrote a different script to handle each form in a series - it's the natural way when you're early in the learning process, but it can lead to repeated code that's hard to follow, and some really horrid complicated conditionals.

On Saturday and Sunday, I demonstrated the restructuring of a "classic" series of scripts into a more robust, more efficient, and more maintainable piece of code - all in a single application (and in a single file in this case). Duplicate code was removed, variables in the session simplified, and by using a "current page number" scheme, a whole host of complex conditionals got shrunk out of existence. I can't publish the final code (as the code on which it was based, thus my derivative, isn't my copyright) but I can talk about it ... and I can point you to a sample of a similar structure - its here

Plan out your application. If you want a system into which people have to log in, or you don't want then to start halfway through, you'll write a single piece of code. Start off your design with a state diagram, showing (in circles) each of the pages that the user may see, then linking them with lines which represent the actual program chunks (your PHP isn't the stuff in the circles - it's the lines BETWEEN them!)


Write the code all in a single top level file - i.e. at a single URL. The code will have a $_SESSION variable which holds the current page so that it knows what to run, and each time the page is called up the actions performed will be:
• a) Validate form inputs / finish up from previous page
• b) Prepare for next page
• c) Complete the template for the next page, send it out

With a small demonstration such as the one we did over the weekend, all the code and even the template can go in a single file - however, as the application grows and as you want to reuse code in other applications you'll want to split it into four files / logical groups:
• 1. The Template for the response page (easily edited with Dreamweaver or similar)
• 2. Web helper routines to help with generation of sticky forms, handling user inputs which include awkward characters such as ' " and <, etc
• 3. "Business" or program logic which relates to the application and calculations and validations that it needs
• 4. Top level code - i.e. the two switch statements that control the whole program's operation.

With a still larger system (let's say you get up to 20 or 30 pages!), you can then load business logic from multiple files, using a 'just in time' technique which will be efficient, rather that loading all the code for every page each time.


Although a 'normal' computer program runs from top to bottom, a web application written as I have described above will run a number of times ... and the way it is structure means that some of the code that's further down the file will be run before code that's higher up, but on a later page. The note in green on the board says "Confusing" - which it might be for the first half hour. Once you're used to it, it's great.




Index

$_SERVER - 2.2
.htaccess - 2.1
C - 1.5
conditional - 4.3
htaccess - 2.1
HTML++ - 2.1
Java - 1.5
mysql - 2.2
MySQL - 4.3
Perl - 1.5
PHP - 1.5
print_r - 2.2
Python - 1.5

Training sample © 2012, WELL HOUSE CONSULTANTS LTD
This is http://www.wellho.net/demo/manual.php
Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
Phone: +44 (0) 1225 708 225 • EMAIL: info@wellho.net • WEB: http://www.wellho.net