For 'not newbies': Try this PHP quiz @ W3Schools first
So far, we have seen various client-side technologies:
However, client-side programming alone is not enough for a full-fledged web application because...
PHP is yet another programming language in this CS3226
It is one of the most popular server-side scripting language in the world (and open source a.k.a. free)
We will write programs on server-side and you will need a PHP-enabled web server (e.g. a LAMP=Linux Apache MySQL PHP stack) to test these programs, e.g. DO droplet that you/your team mate(s) have set up in Lab2
Or, you can install things like (free) XAMPP, WAMPServer, etc on your own computer to run PHP locally (@localhost)...
Let's write our very first PHP code named as 'hello.php'
:
<?php // this is the signal of the start of PHP section
echo 'Hello World, this is my first PHP code'; // this is a comment
// the line below signal the end of PHP section
?>
For this demo, Steven uploads the PHP code to his VA server
Try accessing http://visualgo.net/cs3226/hello.php; Is it OK?
Then check the page source! Is it an HTML(5) document?
A wrongly set up server may cause php document to be displayed as plain text instead of executed... (bad :O)
PS: Laravel has 'shortcut' for those frequent <?php
and ?>
Programming Methodology, but using PHP:
Steven will only show a few of these live demo (using his VisuAlgo server, max approx 10 minutes) and will relegate the details for self exploration during Lab4
<!DOCTYPE html> <!--We can mix HTML, CSS, JS commands inside PHP file-->
<html lang="en">
<head><title>PHP demo</title></head>
<body><?php
$w = 1; $x = 2; $y = 3; $z = 4; // variable names starts with a $ sign
define("FOUR", 4); // this is PHP way to declare a constant
eChO "<p>variables demo<br>\n";
ecHo ($w/$x + $y*$z) . "<br>\n"; // echo 12.5; frequently used command
Echo ($x > $y) . "<br>\n"; // false is not echoed; "." is a concat symbol
ECHO ($x < $y && $z == FOUR) . "<br></p>\n"; // echo 1 (true)
// PHP commands are NOT case sensitive but variable names are...
echo "What is this: [$notexistent]?<br>\n"; // nothing is printed
$w = 'changed to string'; // PHP is not a strongly typed language, like JS
echo $w . "<br>\n";
print ($z%3); // print is similar to echo, % is modulo, prints out 1
PS: We go through vanilla PHP a bit in the event Laravel (PHP framework) becomes unusable (for whatever reason), you can switch to other PHP framework easier
echo "<p>if-else and (cond ? true : false) demo<br>\n";
if ($x > $y)
echo "x is bigger than y<br>\n";
else
echo "x is smaller than y<br>\n";
echo "x is " . ($x > $y ? "bigger" : "smaller") . " than y<br></p>\n";
echo "<p>switch demo<br>\n";
switch ($x) {
case 1: echo "x is 1<br>\n"; break;
case 2: echo "x is 2<br>\n"; break;
default: echo "x is not 1 or 2<br>\n"; break;
}
echo "</p>\n";
echo "<p>for loop demo<br>\n";
for ($i = $x; $i <= $z; $i++) // $x = 2, $z = 4, loop from 2 to 4
echo "i is " . $i . "<br>\n";
// echo "i is $i<br>\n"; // is also possible, notice double quotes
echo "</p>\n<p>while loop demo<br>\n";
$i = 0; // $y = 3
while ($i < $y) // 0, 1, 2 and then stop
echo "i is " . ($i++) . "<br>\n";
echo "</p>\n<p>do-while loop demo<br>\n";
$i = 0; // $y = 3 (different behavior with above if $y = 0)
do
echo "i is " . ($i++) . "<br>\n";
while ($i < $y); // 0, 1, 2 and then stop (notice the ;)
echo "</p>\n";
echo "<p>more complex control flow demo<br>\n";
$a = array(2, 1, 7, 8, 3); // we will discuss array in more details soon
for ($i = $sum = 0; $i < count($a); $i++) // count: to count array length
if ($a[$i]%2 == 0) continue; // an even number, skip this iteration
else if ($sum > 7) break; // stop the associated loop
else $sum += $a[$i];
echo "the sum is $sum<br>\n";
$sum = 0;
foreach ($a as $key => $value) { // foreach loop
if ($sum > 7) break;
$sum += $value%2 == 0 ? 0 : $value;
}
echo "the sum is $sum<br></p>\n";
echo "<p>function demo<br>\n";
require_once("sum.php"); // this is like C/C++ #include (next slide)
$a = array(2, 1, 7, 8, 3);
echo "sum: " . sum($a) . "<br>\n"; // 21
function fib($n = 7) { // recursive function, default argument $n = 7
if ($n <= 1) return $n;
else return fib($n-1) + fib($n-2);
}
echo "fib(6) = " . "<br>\n"; // 8
echo "fib() = " . fib() . "<br></p>\n"; // default argument, fib(7) = 13
<?php // an external file that is included in the previous slide
function sum($a) {
$ans = 0;
foreach ($a as $val)
$ans += $val;
return $ans;
}
?>
// PHP 1D array demonstration
$C = array(13, 1, 12, 5, 7);
array_splice($C, 2, 2, array(8, 4, 6)); // replace [12, 5] with [8, 4, 6]
$l = count($C); // length of array is now 6: [13, 1, 8, 4, 6, 7]
echo $C[5] . "<br>\n"; // 7
sort($C); // sort ascending, already compare by value
echo "sorted: ";
foreach ($C as $val) echo $val . " "; // manual
echo "<br>\n";
echo "compare with: " . implode(" ", $C) . "<br>\n"; // use implode
$D = array("N"=>2, "M"=>3); // PHP associative array ~ an ordered map
echo "Using var_dump:<br>\n";
var_dump($D);
echo "<br>\n";
// PHP 2D array demonstration
$G = array(
array(1, 2),
array(0),
array(0)
);
for ($i = 0; $i < count($G); $i++) {
echo "row $i: ";
for ($j = 0; $j < count($G[$i]); $j++)
echo $G[$i][$j] . " ";
echo "<br>\n";
}
echo "Using var_dump:<br>\n";
var_dump($G);
echo "<br>\n";
// PHP string manipulation demonstration
$str1 = 'steven';
echo strlen($str1) . "<br>\n"; // 6
echo $str1[1] . $str1[3] . "<br>\n"; // 'tv', 0-based indexing
$str2 = 'seven';
echo "strcmp: " . strcmp($str1, $str2) . "<br>\n"; // positive value
echo "eve: " . strpos($str1, "eve") . "<br>\n"; // index 2
echo "ev3: " . strpos($str1, "ev3") . "<br>\n"; // false/not found
$seven = 7;
echo "$seven<br>\n"; // will output: 7
echo '$seven<br>\n'; // will output: $seven<br>\n, notice the difference?
?>
</body>
</html>
Now this can be painful...
When the client requests for a PHP file, the server will execute the PH(Pre-processor) code (pre-process it) before returning an HTML file (although we still see .php in the address bar of our client browser -- unless we set up our server to hide it)
If there is a warning in the PHP script, PHP will continue but logs the warning message in the web server error.log
file (it is in folder /var/log/apache2
if you use LAMP stack on Ubuntu 16.04 @ DO droplet)
For example, the script below will add a warning message at the tail of error.log
<?php $x = 1/0; // division by zero
?>
$ tail -1 /var/log/apache2/error.log # show the last line in error.log [Sun Jan 29 12:57:14.878238 2017] [:error] [pid ????] [client ???.???.???.???:59850] PHP Warning: Division by zero in /var/www/html/cs3226/error.php on line 8
Occassionally check the log file of your web server for such (silent) warning like this because if your web server is not configured properly, you may quickly run out of disk space due to accummulated warning messages
If there is an unrecoverable error, the server cannot execute PHP code further, sends HTTP status 500 (Internal Server Error), (usually) shows a blank page (or partially rendered page), and also logs the error message in the error.log file
Such error usually cannot be handled even with this set_error_handler function (whereas the previous PHP warning can be handled this way)
For example, the script below will add an error message at the tail of error.log
<?php echoes "Hello World"; // unknown PHP command 'echoes'
?>
$ tail -1 /var/log/apache2/error.log # change -1 to -n to get last n lines [Sun Jan 29 12:59:51.149839 2017] [:error] [pid ????] [client ???.???.???.???:59888] PHP Parse error: syntax error, unexpected '"Hello world"' (T_CONSTANT_ENCAPSED_STRING) in /var/www/html/cs3226/error.php on line 8
This time, the web programmer usually reacts faster as his/her PHP code does not work
Debugging server-side PHP code is indeed (much) harder than debugging client-side JavaScript code; but fortunately, Laravel has "debug" mode that we can use during development (turn it off in production for security)
So far, what we have learned in this PHP lecture is similar with the client-side technology: JavaScript other than the fact it is now harder to see the PHP source code
We can use PHP to make the server reacts to client's inputs rather than just serving the same static webpage
PHP can process the information sent by client to server via HTTP GET* or HTTP POST* requests
To do this in PHP is simple, we access its superglobal arrays $_GET
(useful in some cases, e.g. in http://nusmods.com) or $_POST
(recommended method in most cases)
There are a few other PHP superglobal arrays, e.g. $_REQUEST
(combination of $_GET
, $_POST
, and $_COOKIE
), $_SESSION
(will be discussed soon), and some optional ones: $_SERVER
, $_FILES
, $_ENV
, $_COOKIE
, $GLOBALS
(PS: Laravel uses different way to access these)
During the HTML5 lecture, we briefly discussed about the HTML5 forms, mainly about the HTML5 tags to display the form elements, but we have not discuss on how to actually process the data collected from user and we will do so now
A simple form.html and the corresponding form.php
<--client side, a simple form ("form.html")-->
<form method="post" action="form.php">
<p>What is 7 + 3?<br></p>
<input type="radio" name="mcq" value="9">A. 9
<input type="radio" name="mcq" value="10">B. 10
<input type="radio" name="mcq" value="11">C. 11
<input type="submit" name="submit" value="Answer">
</form>
<--server side, form.php-->
<p>You selected: <?php $ans = $_POST["mcq"]; echo $ans;?><br>
Correct: <?php echo ($ans == 10) ? "Y" : "N"; ?><br></p>
Not shown in the simple example above: Always validate/sanitize form input on server-side too even if you have done so in client-side using either HTML5 form elements' settings or JavaScript (but see Laravel version)
In JavaScript lecture, we have seen how to add "state" to the stateless HTTP protocol in client-side: using HTML5 localStorage
(we abandoned HTTP cookies)
We can also add "state" to the stateless HTTP protocol in server-side, using PHP session control
<?php session_start(); must be the first line of your PHP script
$elapsed = 0;
if (empty($_SESSION['count'])) { /* or use !isset */
$_SESSION['count'] = 1;
$_SESSION['visittime'] = time();
}
else {
$_SESSION['count']++;
$elapsed = time()-$_SESSION['visittime'];
$_SESSION['visittime'] = time();
}
echo "You have visited this page " . $_SESSION['count'] . " times<br>\n";
echo session_id() . ", your last visit was " . $elapsed . "s ago<br>\n";
/* this is count.php */ ?>
<?php session_start(); // must still use this first
session_destroy();
echo "Try visiting count.php again<br>\n";
/* this is reset.php */ ?>
More about using session in Laravel framework soon
Several ways to execute PHP script @ web-server:
We will likely pass (complex) data between client and server as JSON, so please study json_encode (convert PHP associative array into JSON to be read by client-side JS) and json_decode (take in JSON from client-side JS and decode it into PHP object that can be cast as associative array)
Now, let's use the same example as with vanilla PHP from this slide as the first illustration on how to use Laravel to easily create forms, use server-side validator :O, and to process the form (for now, without database access)
But first, we need to set up LaravelCollective
package as for some unclear reason, these useful features (in my opinion) are removed from the core framework...
Read this (for Laravel version 5.3, it may change a bit? for the new version 5.4 :O)
{{-- test.blade.php --}}
{!! Form::open() !!} {{-- Blade shortcut for creating HTML5 form --}}
<div class="form-group"> {{-- Group related form components together --}}
{!! Form::label('name', 'What is your name:', ['class' => 'control-label']) !!}
{!! Form::text('name', null, ['class' => 'form-control']) !!}
</div>
<div class="form-group">
{!! Form::label('mcq', 'What is your answer:', ['class' => 'control-label']) !!}
{!! Form::radio('mcq', '9', false, ['class' => 'form-control']) !!}A.9
{!! Form::radio('mcq', '10', false, ['class' => 'form-control']) !!}B.10
{!! Form::radio('mcq', '11', false, ['class' => 'form-control']) !!}C.11
</div>
<div class="form-group"> {{-- Don't forget to create a submit button --}}
{!! Form::submit('Submit', ['class' => 'form-control']) !!}
</div>
{!! Form::close() !!}
// all else standard
use Validator; // we will use this later
class FormController extends Controller {
public function test() { return view('test'); }
public function check(Request $request) {
// ps, yeah, I 'cheat' by combining Controller and View together...
// separate them in your actual project
$name = $request->input('name');
$ans = $request->input('mcq');
return "<p>" . $name . ", you selected: " . $ans . "<br>" .
"Correct: " . ($ans == 10 ? "Y" : "N") . "<br></p>";
}
}
Route::get('test', 'FormController@test');
Route::post('test', 'FormController@check'); // notice the POST method
Now you can test the test
route
The temporary URL is this one
Later in Security lecture, we will talk more about this
Here, we just want to show that it is very easy to add
server-side validation using Laravel
Just add this in function FormController@check
public function check(Request $request) {
$validator = Validator::make($request->all(), [ // as simple as this
'name' => 'required|min:3|max:10',
'mcq' => 'required',
]);
if ($validator->fails()) {
return redirect('test') // redisplay the form
->withErrors($validator) // to see the error messages
->withInput(); // the previously entered input remains
}
// all else the same as before
// Everything else is the same as 'test.blade.php'
// ...
{!! Form::submit('Submit', ['class' => 'form-control']) !!}
</div>
@if (count($errors) > 0) {{-- just list down all errors found --}}
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
{!! Form::close() !!}
Now you can test this version again
Usually we want to store user's (form) input in a persistent storage and a (relational) database is a good solution
Good News: PHP has built-in support to run (My)SQL queries
Even Better News: Laravel, the chosen PHP framework for this semester, has even better Eloquent ORM that can make database access even easier...
In the next Database lecture, we will learn on how to use database in our web application
Things will get much more exciting after this
Same as with the challenge in JS lecture but now in PHP
Can I see the php code?
Same as with the challenge in JS lecture but now in PHP
Can I see the php code?
Now, try this PHP quiz @ W3Schools
header
function (deferred to security lecture)exit
function (defered to SQL lecture)mail
function (defered to Web Server lecture)$_FILES
superglobals