PHP Basics

Maxence POUTORD

RevealJS Tips

Goals

  • PHP Basics
  • Use a template engine
  • Communicate with a MySQL Database
  • Make a web app

PHP: Hypertext Prepocessor

  • 20 years old!
  • 6th langage in the world (TIOBE september 2015)
  • Running on 80% of web server
  • Type of websites:
    • Little: Conserto...
    • Medium: Voyage SNCF, WhiteHouse's Website...
    • Large: Facebook...

Client/Server

  • Client = browser.
    Send request
  • Server = Web server.
    Return response
  • HTTP protocol: Stateless

Installation

  • Linux: sudo apt-get install php5-common libapache2-mod-php5 php5-cli
  • OSX: similar to the Linux installation
  • Windows: avoid WAMP. Use a vagrant box instead (or docker)

RTFM

http://www.php.net

PHP Basic

File example

index.php


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <?php echo "Hello World!"; ?>
  </body>
</html>

Note: every line of PHP must end in ;

Comments


//A single line comment
/*
A multi-line
comment
 */
# Another one line comment (avoid)

Types (1/2)


$nothing   = null;
$firstName = "John";             //with single quote
$lastName  = 'WAYNE';            //with double quote
$name      = "Bruce ".$lastName; //concatenation
$name     .= " aka Batman";      //concatenation
$age       = 51;
$young     = false;
$pi        = 3.14;
$object    = new SomeObject();

echo "Hello $name!";
echo 'Hello ' . $firstName . $lastName .'!';

Types (2/2)


$hobbits = array("Frodo", "Bilbo", "Sam");
$lands[]  = "Shire";   //$lands[0] == "Shire";
$lands[]  = "Rohan";   //$lands[1] == "Rohan";
$lands[1] = "Gondor";  //$lands[1] == "Gondor";
echo "I live in $lands[1]";


$person['name'] = "Frodo";
$person['land'] = "Shire";


//Multidimensionnal array
$persons[0]['name'] = "Frodo";
$persons[0]['land'] = "Shire";
$persons[1]['name'] = "Gandalf";
$persons[1]['land'] = "Gondor";

$array[someIndex][someOtherIndex][someOtherIndex]...[] = $whatever;

Comparison Operators


$a = 42;
$b = 51;
$c = $b;

var_dump($a <= $b);    //true
var_dump($b == $c);    //true
var_dump($b == "51");  //true
var_dump($b === "51"); //false

Conditions


if ($language == "fr") {
    echo "Bienvenue";
} elseif ($language == "en") {
    echo "Hello";
} else {
    echo "Ciao";
}

switch($language) {
    case "fr": echo "Bonjour";
        Break;
    case "en": echo "Hello";
        Break;
    case "it": echo "Ciao";
        Break;
    default: echo "Bonjour";
}

Logical operators

  • $a and $b
  • $a or $b
  • !a
  • $a && $b (like and operator)
  • $a || $b (like or operator)

Loops


for ($i = 1; $i <= 10; $i++) {
    echo $i;
}
//1 2 3 4 5 6 7 8 9 10

$i = 0;
while (i <= 10) {
    echo $i;
    $i++;
}
//0 1 2 3 4 5 6 7 8 9 10

$fruits = array("banana", "apple", "cherry");
foreach ($fruits as $aFruit) {
    echo $fruit;
}
//banana apple cherry

Functions (1/2)


$phrase = "Java is great!";
echo str_replace("Java", "PHP", $phrase); //"PHP is great!"
echo "We are ".date('d m Y');
A lot of String functions: http://php.net/manual/fr/ref.strings.php
Same for date functions: http://php.net/manual/fr/ref.datetime.php

Functions (2/2)


function sayHello($name) {
    echo "Hello $name!";
}
sayHello("World"); //Hello World!

function cube($var) {
    return $var * $var * $var;
}
$myVar = cube(4); //$myVar == 64

Errors

Constant Description
E_ERROR Fatal run-time errors. Execution of the script is halted
E_WARNING Non-fatal run-time errors. Execution of the script is not halted
E_NOTICE Run-time notices. The script found something that might be an error, but could also happen when running a script normally

Turn off error in production environment!

Catching errors


try {
    echo 1/0;
} catch (Exception $e) {
    echo "Can't divide by zero";
    echo $e;
}

Mail


$headers  = "From: Barack OBAMA <barack.obama@whitehouse.gov>";
$headers .= 'Content-type: text/html; charset=utf-8';

if (mail('kim-jong-un@korea-dpr.com', 'Hi guy', 'Hey, I\'m ready to fight', $headers)) {
  echo "OK. Nulclear war is ready!";
} else {
  echo "KO";
}

Work with files


$headers  = "From: My name <contact@me.fr>";
$headers .= 'Content-type: text/html; charset=utf-8';

$myFile = fopen('mailingList.txt', 'r');
while (($line = fgets($myFile)) !== false) {
    mail($line, 'Hello', 'Visit my new website!', $headers)
}
fclose($myFile);
Mode Details
r Read
r+ Read/Write
a Read. Create if not exist.
a+ Read/Write. Create if not exist.

Work included files

Why ?

  • Avoid copy/paste errors
  • Improve code readability...
  • ...and maintainability

What ?

  • HTML Elements
  • PHP Functions, classes...

Example (1/2)

Example (2/2)

Including files

4 ways:

  • include 'myFile.php': will include myFile.php
  • require 'myFile.php': identical to include, but produce a fatal error on failure
  • include_once/require_once 'myFile.php': identical to include/require, but check if the file has already been included, and if so, not include (require) it again

//vars.php
$film = "Batman";
//index.php
include 'vars.php';
echo "I'm watching $film"; //I'm watching Batman

Twig

in a nutshell:


//Before

<?php echo $var; ?>


{# After #}

{{ var }}

TWIG syntax (1/2): Before


<ul>
    <?php
    if (count($users) > 0) {
        foreach ($users as $aUser) {
            echo "<li>".$aUser['name']." live in ".$aUser['city']."</li>";
        }
    } else {
        echo "<li>no user found</li>";
    }
    ?>
</ul>
			

TWIG syntax (2/2): After


    {% for aUser in users %}
  • {{ aUser.name }} live in {{ aUser.name }}
  • {% else %}
  • no user found
  • {% endfor %}

Some TWIG filters


{{ "now"|date("m/d/Y") }} // 2/11/2015

{{ 'abcd...'|reverse }} //...dcba

{{ '12345'|slice(1, 2) }} //23

{{ 101.51|round }} //102

{# Multiple filters#}
{{ 'abcd...'|slice(1, 2)|reverse }} //cb

		

PHP/HTML separation&new workflow

Using TWIG


//kernel.php
include_once('../Twig/lib/Twig/Autoloader.php');
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem(__DIR__."/../views"); // view folder
$twig = new Twig_Environment($loader, array(
    'cache' => false
));

//script.php
include_once('kernel.php');
$template = $twig->loadTemplate('welcome.html.twig');
echo $template->render(array(
	'user'     => $user,
	'whatever' => $whatever
));
		

Code separation


//layout.html.twig
<!DOCTYPE html>
<html>
  <head>...</head>
  <body>
    {% block body %}{% endblock %}
  </body>
</html>

//welcome.html.twig
{% extends "layout.html.twig" %}
{% block body %}
{% if user %}
    

Welcome {{ user }}!

{% endif %} {% endblock %}

Getting started

Sending data from client to server

Retreive from <form> HTML element (method POST)


echo $_POST['role']; echo $_POST['name'];

Retreive from URL (method GET)


http://www.mywonderfulapp.com/script.php?firstname=john&lastname=doe&age=42
echo $_GET['firstname'], " ", $_GET['lastname'], $_GET['age']; //john doe 42
			

Example:

Never trust user input: XSS


echo $_GET["message"];
		
echo htmlspecialchars($_GET["message"]); //PHP
{{ message }} //twig
		

Never trust user input: SQL Injection

Never trust user input: $_GET & include


include "include/".$_GET["page"].".php";

//http://www.vulnerable_host.com/preview.php?page=../../../../etc/passwd%00

Data manipulation from Database (MySQL)

PHPMyAdmin

  • Web software to handle the administration of MySQL
  • Manage table, data...
  • ...it's free!
  • Demo

PDO (1/5): In a nutshell

PDO = PHP Data Object

Secure request

PDO (2/5): Connection&Retreive data


try {
    $bdd = new PDO('mysql:host=localhost;dbname=test;charset=utf8',
                  'root', 'root');

    $reponse = $bdd->query('SELECT * FROM beers');
    $data = $reponse->fetchAll();

} catch(Exception $e) {
    die("Cannot connect to database server");
}
			

Now $data is an array of beers

PDO (3/5): Retreive data


$request = $bdd->prepare("SELECT * FROM beers WHERE id = :id");
$request->execute(array(
  ':id' => $_GET['id']
));
$aBeer = $request->fetch();
			

Now $data contain one beer

PDO (4/5): Prepared statements

Avoid SQL Injection


$request = $bdd->prepare("INSERT INTO beers (name, description)
                       VALUES (:name, :description)");
$request->bindParam(':name', $name);
$request->bindParam(':description', $description);

$name = "Mélusine Bière de Noël";
$description = "Merry christmas!";
$request->execute();

$name = "Kronembourg";
$description = "You get what you pay for...";
$request->execute();
			

PDO (5/5): other CRUD request


//UPDATE
$sql = 'UPDATE beers set name=:name where id=:id';
$request = $bdd->prepare($sql);
$request->execute(array(
    ':name' => 'Grimbergen',
    ':id' => 1
));

//DELETE
$sql = 'DELETE from beers where id=:id';
$request = $bdd->prepare($sql);
$request->execute(array(':id' => 1));
		

The end

Well... maybe not!

How to be a better developper ? (1/2)

Don't copy/past like an idiot

How to be a better developper ? (2/2)

Coding standards

Try to stick PSR Standard Recommendations

http://www.php-fig.org

Security

OWASP Top 10

Performances with Blackfire

Blackfire.io

Use Framework

Why ? Improve...

  • Security
  • Velocity
  • Code organisation
  • Code quality (?)

I recommend Symfony2 (most popular in France)

See more

There is no end ;-)

Keep moving: https://www.codecademy.com/tracks/php

Thank you

Questions ?