Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
384 lines (271 sloc) 8.74 KB

Practical Work #1

The goal of this practical is to learn the PHP language by playing with it. You should focus on understanding how things work rather than trying to do things by yourself, especially because most of the work is already done. Be sure to understand everything before starting the exercises!

Interactive Command Line

1. Hello World

PHP embeds a nice interactive shell that is often underused, because developers don't really know about it. However, in most cases, it is really handy as it allows you to quickly write and execute PHP. Unfortunately, it is not a real Read-Eval-Print-Loop (REPL) per se. Boris is a real and powerful REPL for PHP. Facebook has its own interactive shell too: phpsh.

In the following, you will use the default PHP interactive shell though, it is not a big deal for what you will have to do anyway.

$ php -a
Interactive mode enabled

php >

Type:

php > echo "hello world\n";

Now, hit enter to execute your first line of PHP. You should get the following result:

hello world

Now, execute the following line in the shell :

php > echo sprintf("Hello %s\n", "Votre prenom");

Hit enter:

Hello Votre prenom

To quit the shell, just type quit or exit at the php prompt.

The PHP command line is also able to execute PHP code directly from the command line thanks to the -r option:

$ php -r 'print "hello world\n";'
hello world

This is particularly useful when you have to deal with OS restrictions. For instance, Composer, the PHP package manager, uses php -r "file_get_contents('...');" to download files on Windows machines because curl or wget don't exist by default.

2. Variables

Back to the PHP interactive shell, declare your very first variable:

php > $a = 1;
php > var_dump($a);

The result should be:

int(1)

Now, declare two variables:

php > $a = 1;
php > $b = 3;
php > printf("%d + %d = %d\n", $a, $b, $a + $b);

The result should be:

1 + 3 = 4

Working with strings is easy:

php > $b = "foo";
php > var_dump($b);

The result should be:

string(3) "foo"

print_r() is another function to print variables:

php > $b = "foo";
php > print_r($b);

The result should be:

foo

var_export() is a function that formats a variable. You can pass an optional argument, be sure to understand why:

php > $b = "foo";
php > echo var_export($b, true);
php > var_export($b);

The result should be:

'foo'
'foo'

3. Include

Somewhere in your home directory, create a shell.php file and insert the following content:

<?php
$foo = 1;

Then, try to execute the following code in the interactive shell:

php > var_dump($foo);

You should get the following result:

PHP Notice:  Undefined variable: foo in php shell code on line 1
PHP Stack trace:
PHP   1. {main}() php shell code:0

Notice: Undefined variable: foo in php shell code on line 1

Call Stack:
    3.4535     221408   1. {main}() php shell code:0

NULL

Now, include your file:

php > include "/path/to/shell.php";
php > var_dump($foo);

The result should be:

int(1)

Cli Programs

It is possible to execute PHP code directly from the command line by giving php command a file as first argument:

$ php file.php

You can also use the #!/usr/bin/env php shebang and make the file a script à la shell script:

$ echo '#!/usr/bin/env php' > /path/to/your/php/file.php
$ chmod a+x !$

Executing such a script would be doable by running:

$ /path/to/your/php/file.php

Remember that running php file.php will always work though.

Exercises!

Hello, World!

Write "Hello, World!" to the console using a PHP script that can be executed by running the following commands:

$ php hello.php
// should output: "Hello, World!"

$ ./hello.php
// should output: "Hello, World!"

User Interactions

Write a script that takes your name as first argument, and print:

Hello, <your name>!

Client and Server

MVC Architecture

Let's create a few directories and files:

$ mkdir -p ~/php/tp1/{public,model,view}
$ touch ~/php/tp1/public/cities.php ~/php/tp1/model/cities.php ~/php/tp1/view/cities.php
<?php
// ~/php/tp1/public/cities.php

// include model
include __DIR__ . '/../model/cities.php';

// include view
include __DIR__ . '/../view/cities.php';
<?php
// ~/php/tp1/model/cities.php

$cities = array(
    [ "name" => "San Francisco", "country" => "USA"       ],
    [ "name" => "Paris",         "country" => "France"    ],
    [ "name" => "New york",      "country" => "USA"       ],
    [ "name" => "Berlin",        "country" => "Germany"   ],
    [ "name" => "Bamako",        "country" => "Malia"     ],
    [ "name" => "Buenos Aires",  "country" => "Argentina" ],
    [ "name" => "Santiago",      "country" => "Chile"     ],
    [ "name" => "Bombay",        "country" => "India"     ],
    [ "name" => "Vancouver",     "country" => "Canada"    ],
);
<!-- ~/php/tp1/view/cities.php -->
<!DOCTYPE HTML>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>All Cities</title>
    </head>
    <body>
        <h1>All Cities</h1>
        <table>
        <?php foreach ($cities as $cityId => $city) : ?>
            <tr>
                <td><a href="/city.php?id=<?= $cityId; ?>"><?= $city['name']; ?></a></td>
                <td><?= $city['country']; ?></td>
            </tr>
        <?php endforeach; ?>
        </table>
    </body>
</html>

Using another terminal, use the PHP embedded webserver to run your code:

$ cd ~/php/tp1
$ php -S localhost:8090 -t public/

Important: not sure how etud behaves, so you may have to choose another port number because 8090 is already in use.

Now, you can open http://localhost:8090/cities.php.

Add A Dynamic Controller

Let's define a page to present a city. You need:

  • a front controller (dynamic controller);
  • a view template;
  • a 404 page if the city does not exist (in your dataset).
<?php
// ~/php/tp1/public/city.php

include __DIR__ . '/../model/cities.php';

/**
 * render a 404 page
 */
function page_not_found()
{
    header("HTTP/1.0 404 Not Found");
    include __DIR__ . '/../view/404.html';
    die();
}

// retrieve id from url parameter
$cityId = $_GET["id"];
if (!isset($cityId) || !is_numeric($cityId) || !isset($cities[$cityId])) {
    // No id given or invalid id
    page_not_found();
}

// retrieve city from dataset
$city  = $cities[$cityId];
// define some more variables
$title = sprintf("City %s", $city["name"]);

// include view
include __DIR__ . '/../view/city.php';
<!-- ~/php/tp1/view/city.php -->
<!DOCTYPE HTML>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title><?php echo $title ?></title>
    </head>
    <body>
        <h1><?php echo $city["name"] ?></h1>
        <footer>
            <a href="/cities.php">Back to list</a>
        </footer>
    </body>
</html>
<!-- ~/php/tp1/view/404.html -->
<!DOCTYPE HTML>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>404 Not Found</title>
    </head>
    <body>
        <h1>404 Not Found</h1>
        <h2>We are unable to find the city you are looking for :-(</h2>
        <p>Please accept this gif as an apology:</p>
        <p><img src="https://raw.github.com/willdurand-edu/php-practicals/master/src/images/nyan.gif" /></p>
        <footer>
            <a href="/cities.php">Back to list</a>
        </footer>
    </body>
</html>

Open http://localhost:8090/cities.php, and click on some cities.

Open http://localhost:8090/city.php?id=-1 and see the result.

Exercises!

Filter Cities By Country

Add a link to the country list and create a page for a country, listing all its cities.

Data Store

Read cities from a CSV file:

San Francisco;USA
Paris;France
New york;USA
Berlin;Germany
Bamako;Malia
Buenos Aires;Argentina
Santiago;Chile
Bombay;India
Vancouver;Canada

You may need filesystem related functions, and the explode function.

OOP

Create two classes: City and Country. Add the appropriate properties and methods, then implement the relation described below:

Refactor your code to use these two classes. It looks like a good idea to wrap the code that reads the CSV file, and creates objects into a class too.