This is not the PHP of old. Learn what's changed in the PHP world over the last few years. Classes, objects, statics, traits, unit testing, composer, password hashing, standards; it's a whole new ballgame.
PHPmodern& secure
View Slide
Who is this guy?Ben EdmundsOpen SourceAuthorPHP Town Hall PodcastCTO at Mindfulware
Who is this guy?Ben Edmunds@benedmundshttp://benedmunds.com
Welcome tothe Future
Great Scott!
Welcome to the FuturePDOClosuresNamespaces
Welcome to the FutureAnonymous ClassesTraitsInterfaces
Welcome to the FutureNull CoalescingScalar Type HintsReturn Type Declarations
Welcome to the FutureVariadic FunctionsAuthenticationPassword Hasing
Welcome to the FutureSQL InjectionHTTPS
Welcome to the FutureCommon Hacks
Legit ToolsBuilt-in ServerComposerUnit Testing
StandardsPHP-FIGPSRs
Exceptions
Exceptionstry {//your code goes here}catch (Exception $e) {die($e->getMessage());}
ErrorsException implements ThrowableError implements Throwable
Errorstry {//error thrown here}catch (Error $e) {die($e->getMessage());}
Errorstry {//error thrown here} catch (Error $e) {die($e->getMessage());} catch (Exception $e) {die($e->getMessage());}
Errorstry {//err or excpt thrown here} catch (Throwable $t) {die($t->getMessage());}
Errorstry {//error or excpt thrown here} catch (Error | Exception $e) {die($e->getMessage());}
Namespaces
Namespacesnamespace Illuminate\Console;class Command{//…
Namespacesuse Illuminate\Console\Command;namespace Illuminate\Console;class Command{//…
PDO
PDOCross SystemSafe Binding
PDO$stmt = $db->prepare(‘SELECT * FROM usersWHERE id=:id’);$stmt->bindParam(‘:id’, $id);$stmt->execute();
Traits
Traits// grouping without // strict inheritancetrait baseUser {function getName() {return ‘Jon Snow’;}}
Traitsclass adminUser {use baseUser;}
Traits$adminUser = new adminUser;echo $adminUser->getName();//output = ‘Jon Snow’
Traitstrait Loggable {function log($msg) {echo $msg;}}
Traitsclass Post {function get($id) {return $this->db->get($id);}}
Traitsclass Post {use Loggable;function get($id) {$this->log('Getting post ' . $id);return $this->db->get($id);}}
Traits$postModel = new Post;$myPost = $postModel->get(1);//output = ‘Getting post 1’
Traitsclass Post extends Model{use SoftDeletes;}
Interfaces
InterfaceClass myLogger{public function log($msg) {echo $msg;} }
Interfaceinterface Logger{public function log($msg); }
InterfaceClass myLogger implements Logger{public function log($msg) {echo $msg;} }
Closures
ClosuresRoute::get(‘/', function(){return View::make(‘index');});
Closures$input = [1, 2, 3, 4, 5, 6, 7, 8];$output = array_filter($input, function($v){return $v > 5;});// [6,7,8]
Closures$input = [1, 2, 3, 4, 5, 6, 7, 8];$output = array_map(function($n){return number_format($n * 10, 2) . '%';}, array_filter($input, function($v){return $v > 5;}));// ['60.00%', '70.00%', '80.00%']
AnonymousClasses
Anonymous Classestrait Loggable {function log($msg) {echo $msg;}}
Anonymous Classesinterface Logger{public function log($msg);}
Anonymous Classestrait Loggable {protected $logger;function setLogger(Logger $logger) {$this->logger = $logger;}function log($msg) {$this->logger->log($msg);}}
Anonymous Classesclass Post { use Loggable; }$post = new Post;
Anonymous Classesclass Post { use Loggable; }$post = new Post;$post->setLogger(new class implements Logger {public function log($msg) {echo date('m/d G:i') . ': ' .$msg;}});
Anonymous Classes$postModel = new Post;$myPost = $postModel->get(1);//output = ‘09/08 16:20: Getting post 1’
NullCoalescingOperator
Null Coalescing$val = isset($_GET[‘val’]) ? $_GET[‘val’] : 'default';
Null Coalescing$val = $_GET['val'] ?? 'default';
Types!
Scalar TypeHinting
Typesdeclare(strict_types=1);function addNums(float $a, float $b) {return $a + $b;}
Typesdeclare(strict_types=1);function addNums(float $a, float $b) {return $a + $b;}addNums(2, "1 week");// Fatal error: Uncaught TypeError:Argument 2 passed to addNums() mustbe of the type float, string given
Typesfunction addNums(float $a, float $b)addNums(2, "1 week”);// Fatal error: Uncaught TypeError:Argument 2 passed to addNums()must be of the type float, string given
Typestry {addNums(2, "1 week”);}catch(TypeError $e) {}
Typestry {addNums(2, 1);}catch(TypeError $e) {}//3
Typesclass/interfacearraycallableboolfloatintstringobject
Return TypeDeclarations
Typesfunction addNums(float $a, float $b) : int {return $a + $b;}
Typesfunction addNums($a, $b) : int {return $a + $b;}addNums(1.5, 1);// Fatal error: Uncaught TypeError: Return value ofaddNums() must be of the type integer, floatreturned
Typesfunction addNums(float $a, ?float $b) : int {return $a + $b??0;}addNums(1, null);// int(1)
Typesfunction addNums(float $a, ?float $b) : ?int {return $a + $b??0;}addNums(1, null);// int(1)
Typespublic function log($msg) : void {Logger::write($msg);}
VariadicFunctions
Scalar Typesfunction addNums(float $a, float $b) : int {return $a + $b;}
Variadic Functionsfunction addNums(...$numbers) : int {return array_sum($numbers);}addNums(1, 2, 3, 4);// int(10)
Variadic Functionsfunction addNums(float …$numbers) : int {return array_sum($numbers);}addNums(1, 2, 3, 4);// int(10)
Security
HTTPS
HTTPSEncrypts traffic across the wireTrusted send and receiverRequired by OAUTH 2
HTTPShttps://letsencrypt.org/
Authentication
Security//authentication - access controlif (!$user->inGroup(‘admin’)) {return ‘ERROR YO’;}
Security//authentication - brute forceif ($user->loginAttempts > 5) {return ‘CAUGHT YA’;}
Passwords
Passwords//safe password hashingpassword_hash($_POST['pass'], ALGO);
Passwords//safe password hashingpassword_hash($_POST['pass'], ALGO);//password verificationpassword_verify($_POST['pass'], $u->pass);
Passwords//safe password hashingpassword_hash($_POST['pass'], ALGO);//password verificationpassword_verify($_POST['pass'], $u->pass);//password rehashingpassword_needs_rehash($u->pass, ALGO);
Passwordsif (password_verify($_POST['pass'], $u->pass)) {if (password_needs_rehash($u->pass, PASSWORD_DEFAULT)) {$u->pass = password_hash($_POST['pass'],PASSWORD_DEFAULT);$u->save();
Safe Defaults
Security//safe defaultsclass Your Controller {protected $var1 = ‘default value’;function __construct() { … }}
Security//safe defaults$something = false;foreach ($array as $k => $v) {$something = $v->foo;if ($something == ‘bar’) { … }}
Securityfunction addNums(float $a, float $b) : int {return $a + $b;}$something = [];foreach ($array as $v) {$something[] = addNums($v[0], $v[1])}
CommonHacks
Security//Non-Persistent XSShttp://www.yourSite.com/?page_num=2&per_page=50Send the link to someone, boom
Security//Persistent XSSSame idea, except with data that issaved to the server and re-displayed
Security//escaping input$stmt->bindParam(‘:id’, $id);
Security//escaping input$stmt->bindParam(‘:id’, $id);//escaping outputhtmlentities($_POST[‘name’]);
Security//escaping inputClass myModel extend Model {function save($id) {$stmt = $this->query->insert();$stmt->bindParam(‘:id’, $id);$stmt->execute();}}
Security//escaping outputTitleHello =htmlentities($name)?>
Security//Cross Site Request Forgery//(CSRF)http://yourSite.com/users/12/delete
Security//CSRF ProtectionPOST / PUT / UPDATE / DELETEbehind forms with one-time usetokens
Security//CSRF Protectionfunction generateCsrf() {$token = mcrypt_create_iv(16,MCRYPT_DEV_URANDOM);Session::flash('csrfToken', $token);return $token; }
Security//CSRF Protectionfunction generateCsrf() {$token = bin2hex(random_bytes(16));Session::flash('csrfToken', $token);return $token; }
Security//CSRF Protectionif ($_POST['token'] == Session::get(‘csrfToken')) { … }
Legit Tools
Built-inWeb Server
Built-in Server$ php -S localhost:8000PHP 5.7.0 Development Server started…Listening on localhost:8000Document root is /home/ben/htdocsPress Ctrl-C to quit
Composer
AnotherPackage Manager!?
ComposerSane PackageManagementAutoloading via PSR4
Composer/ composer.json{"require": {"stripe/stripe-php": "dev-master","twilio/sdk": "dev-master"}}
Composer$ php composer.phar install-> composer.lock
Composer$ php composer.phar install-> composer.lockCommit it ^
Composer$ php composer.phar install/composer.lock
Composer$ php composer.phar update/composer.json
Composer$client = new Services_Twilio($sid, $tkn);$client->account->messages->sendMessage(…)
Unit Testing
Unit TestingPHPUnitBehatMinkSeleniumCodeCeptionPHPSpec
Unit Testingclass ApiAuthTest extends PHPUnit_Framework_TestCase {public function testVerify() {$auth = new apiAuth();$this->assertTrue($auth->verify());
Unit Testing$ phpunit testsPHPUnit 3.3.17 by Sebastian Bergmann.Time: 0.01 secondsOK (1 tests, 1 assertions)
Standards
StandardsPHP-FIGFrameworkInteropGroup
StandardsMember ProjectsZendSymfonyCakePHPMagentoJoomlaDrupal
StandardsPSRsPHPStandardsRecommendation
StandardsPSRsAutoloadingInterfacesStyle Guides
StandardsPSRsPSR-4: AutoloadingPSR-1: Basic Coding StandardsPSR-2: Coding Style GuidePSR-7: HTTP Message InterfacePSR-6: Caching InterfacePSR-3: Logger Interface
Resources
ResourcesPHP.net
ResourcesModern FrameworksLaravelSymfony2SlimPHPCake PHP
Resourcesleanpub.com/phptherightwayPHPtheRightWay.com
ResourcesGive Me $$$SecuringPhpApps.com SecuringNodeApps.com
Q/A TIME!https://joind.in/talk/83929Ben Edmunds@benedmunds