PHP Basics and Shopping Cart Example

Johann Mitlöhner, 2014-2020

Installation and Use

The programming language PHP (Personal Homepage; PHP Hypertext Preprocessor) is widely used in websites that employ server-side programming (cf. w3techs).

Server-side means that the code is executed on the server; the client (the web browser) only sees the result i.e. the HTML output of the PHP code.

On Linux systems the PHP module for the Apache web server and additional software for PostgresQL database access can be installed (if necessary) with the package manager, e.g. in Debian/Ubuntu/Mint packages libapache2-mod-php and php-pgsql. For the R examples you also need the R software.

Typical web server configuration:

In your public_html directory create a file such as hello.php and enter the following code:

Hello from PHP:
<?php echo 'Hello World!'; ?>

In your browser enter the following into the location bar to access that page (note that some web servers use different URL patterns for user web pages):

http://servername/~userid/hello.php

In our current configuration: https://studentweb.cluster.ai.wu.ac.at/~h12345678/hello.php

Usually the web server is configured to read a file index.html or index.php as default for a directory; in that case you can leave out the file name from the URL.

PHP sections are marked like this: <?php some-code-goes-here ?>

A useful summary of PHP related details is available via

<?php phpinfo(); ?>

SQL Select

The following script produces a list of products from a PostgresQL database table prod:

<?php include 'header.php'; ?>
<h2>Products</h2>

<table>
<tr><th>ID<th>Name<th>Price<th>
<?php
$query = 'select id, name, price from prod';
$result = pg_query($query) or die('Query failed: ' . pg_last_error());
while ($x = pg_fetch_object($result)) {
    echo "<tr> <td> $x->id <td> $x->name <td align=right> $x->price <td> \n";
}
pg_free_result($result);
pg_close($dbconn);
?>
</table>

Note that

The content of our header.php is:

<?php
$dbconn = pg_connect("host=myhost dbname=mydb user=myuser password=mypw")
    or die('Could not connect: ' . pg_last_error());
?>
<meta charset=utf-8>
<link rel=stylesheet href=style.css>

The connection to the database is made; obviously you have to supply your own credentials for dbname, user and password. This file will be executed on the server; the browser will not see the PHP code with the password, only the output (the meta tag and the stylesheet link).

Charset and Encoding

The meta/charset line is used for UTF-8 encoded text containing non-ASCII characters, e.g. German umlauts.

Nowadays all application components (Postgres database, Apache web server, PHP processor, and browser) should interpret UTF-8 correctly. However, the character set in the browser is often set to other defaults, such as ISO 8859-1; in that case non-ASCII characters such as German umlauts are displayed incorrectly; such problems are avoided by

Style

The style sheet style.css contains common layout options for all web pages of this application to provide a consistent look. Here is a very simple example:

body { margin: 5%; }

The option margin for the element body is set to 5%. Other options for HTML elements are set in a similar fashion, e.g. background colors and font sizes.

Of course you can put other PHP and HTML statements in the header.php file as well, e.g. a menu list or icons and banners. If you want similar elements at the bottom of the page you can include a trailer.php file. By combining included files and CSS you can easily create a uniform and professional look for your application.

SQL Insert

Entering data is a two-step process:

The first step is static HTML only:

<h2>Enter new product:</h2> <form action=insertproduct.php method=POST> <table> <tr> <td> ID: <td> <input type=text name=id> <tr> <td> Name: <td> <input type=text name=name> <tr> <td> Price: <td> <input type=text name=price> <tr> <td> Stock: <td> <input type=text name=stock> <tr> <td> <td> <input type=submit value=OK> </form>

The insert script only makes sense when called as action from an HTML form. The script insertproduct.php takes the form input and constructs an SQL Insert statement:

<?php include 'header.php'; pg_query("insert into prod (id, name, price, stock) values ('$_POST[id]', '$_POST[name]', $_POST[price], $_POST[stock])"); echo "Ready."; ?>

PHP Strings can extend over several lines. Complicated SQL statements should be written in a manner that is easy to read and understand. A clear layout greatly simplifies maintainance. It may take a little longer to write, but the investment pays off hugely in terms of fewer bugs.

Single quotes are used inside the SQL statement to delimit text values. Price and stock are numerical values, so they do not need quotes.

Processing form input is a major security problem. In real-world applications it is necessary to use some protection, such as htmlspecialchars($_POST['name']) or similar. Otherwise it is easy for attackers to inject malicious code.

Session IDs

In many situations we would like to track users without requiring login or registration, e.g. for a shopping cart: we do not need the users' real names, we only have to make sure that several simultaneous users see their own respective shopping carts.

Session IDs are 32-character strings used to identify sessions and therefore users:

Session IDs are generated to be unique. Temporary use in tables such as shopping carts is unlikely to cause problems; however, in the long term the uniqueness cannot be guaranteed. SQL sequences provide a clean and reliable solution as a source of unique identifiers.

The variable $_SESSION can hold additional values for use in the application, e.g.

$_SESSION['favcolor'] = 'green';

Passing Parameters in the URL

Sometimes it is convenient to pass a parameter to a script as part of the URL pointing to that script, e.g. when generating a product list with links to a script incart.php to put a product into the shopping cart.

For this purpose, the link to the script incart.php has to be generated as part of the product list:

... while ($x = pg_fetch_object($result)) { ... <td> <a href=incart.php?prod=$x->id>Buy</a> ...

The script incart.php gets the product id from the URL via the $_GET variable and executes an SQL insert statement:

<?php session_start(); ?> <?php include 'header.php'; ?> <?php $sess = session_id(); $query = "insert into cart (sess, prod, qty) values ('$sess', '$_GET[prod]', 1)"; $result = pg_query($query) or die('Query failed: ' . pg_last_error()); echo "<p> Product is in the shopping cart.\n"; ?>

Note that the call to session_start() must be the first PHP command.

Upsert: Update or Insert

In some cases we want to update a row if it exists, or insert a new one if it doesn't; one way to do this is the trial update and counting the affected rows:

if (pg_affected_rows(pg_query("update ... ")) > 0) { echo "Updated ..."; } else { pg_query("insert into ..."); echo "Inserted ..."; }

If the update is successful, one or more rows will be affected, otherwise the else part executes the insert. Note that an update affecting no rows is not an error.

Calling R from PHP

To call the statistical software R from PHP we need an R script file, and the PHP page to run that code. A very simple method for passing the result is shown.

In this sample R script a database connection is used to access a table via an SQL statement. Put the R script in a file chi.r in the same directory with the PHP pages. The code executes an SQL query, outputs the count data, and runs a Chi square test on it:

library(RPostgreSQL) drv <- dbDriver("PostgreSQL") con <- dbConnect(drv, user="...", password="...", dbname="...", host="localhost") res <- dbGetQuery(con, "select count(*) from prod group by price > 10"); attach(res) count chisq.test(count) Security warning: this solution puts the database password in a plain text file readable by the web server. A slightly more elaborate version avoids this problem:
pw <- scan("/path-to-home/pgpass", what="")
con <- dbConnect(drv, user="...", password=pw, dbname="...", host="localhost")

Here the password is put into a text file pgpass in the home directory, where it is not readable by the web server, but R can still access it.

The following PHP code displays the result in the same manner as in the interactive R session (the PRE tags retain the line breaks):

<?php echo shell_exec("Rscript chi.r"); ?>

More sophisticated reporting will use the test results for further processing, e.g., generating text and HTML tags depending on the p-value.

The online documentation of R reveals the names of the individual test values, and the method to access only the p-value.

Save the test result and print only the p-value from R:

...
t <- chisq.test(count)
cat(t$p.value)

Then store the p-value from R in a PHP variable:

<?php $pval = shell_exec("Rscript chi.r"); ?>

Now subsequent PHP blocks can use the variable $pval for statements such as this:

<p> The p-value is <?php echo $pval; ?>

Notes:

Passing several results

In R output the values with cat() and use some separation character in between:

... t <- cor.test(..., ...) cat(t$estimate) cat(":") cat(t$p.value)

The PHP page receives the values from the exec() call and splits the values using the separation character:

<?php $res = shell_exec("Rscript cor.r"); list($cor, $pval) = explode(":", $res); ?>

Automated Reports

With this technique reports can be generated automatically, including text blocks depending on the statistical results. Use CSS for a more professional-looking layout.

<?php $alpha = 0.05; ?> <p> Correlation = <?php echo $cor; ?> <p> p-value = <?php echo $pval; ?> <p> The correlation is <?php if ($pval > $alpha) { echo " not "; } ?> significant at ? = <?php echo $alpha; ?>

Note that the significance level $alpha is set at the begin of the block. This is good programming practise; do not hardcode this value later in the program, as it will be needed several times. When changes to the code are made at a later point in time it will be much easier to maintain and less error-prone if $alpha is set at exactly one point and used consistently everywhere else.

The HTML entity ? produces the Greek letter alpha.

Check the section Other in the R text for further topics on PHP and R integration.

Further Reading

The primary source for everything PHP is php.net.

Prospective developers of real-world applications should take a close look at the section security.

Examples