Sie sind auf Seite 1von 260

PHP Knowledge

PHP.earth

Generated on 2017-08-06

Contents
What is PHP? Where should I start? 18
Where to start? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Where to go next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

PHP evolution 19
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

How to install PHP? Which version of PHP to use? 20


PHP versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
PHP installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Windows installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
OS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Linux installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Third-party Linux repositories . . . . . . . . . . . . . . . . . . . 21
Virtualization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

Why choose PHP? 22


PHP compared to other programming languages . . . . . . . . . . . . 22
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

Which books are recommended for learning PHP? 22


Free PHP books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Paid PHP books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

Which hosting service should I use for PHP? Are there any free
hosting providers? 24
Types of web hosting . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Shared hosting . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
VPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Dedicated server . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

1
Collocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Cloud hosting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Free PHP hosting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

PHP basics 25
PHP in a nutshell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Basic syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Hello world . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Control structures . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Built-in types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
PHP errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
What is next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

PHP 7 33
Why PHP 7 and not PHP 6? . . . . . . . . . . . . . . . . . . . . 33
Major changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Uniform variable syntax . . . . . . . . . . . . . . . . . . . . . . . 34
Exceptions in the engine . . . . . . . . . . . . . . . . . . . . . . . 35
Scalar type declarations . . . . . . . . . . . . . . . . . . . . . . . 35
Combined comparison (spaceship) operator . . . . . . . . . . . . 36
Easy user-land CSPRNG . . . . . . . . . . . . . . . . . . . . . . 36
Null coalescing operator . . . . . . . . . . . . . . . . . . . . . . . 37
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

PHP versions usage 37


PHP version requirements in open source . . . . . . . . . . . . . . . . 38
Why is upgrading PHP important? . . . . . . . . . . . . . . . . . . . . 38
What to do? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

Why does PHP use a dollar sign $ to prefix variables? 39


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

What is object oriented programming (OOP)? 40


Object oriented concepts . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Defining classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Creating class instances . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Calling class methods . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

2
Constructor methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Destructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Methods overriding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Public members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Private members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Protected members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Class constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
The static keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
The final keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Calling parent constructors . . . . . . . . . . . . . . . . . . . . . . . . 50
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

Abstract classes in PHP 51


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

What are iterators in PHP and how to use them? 53


Using the Iterator interface . . . . . . . . . . . . . . . . . . . . . . . . 54
Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Using IteratorAggregate interface . . . . . . . . . . . . . . . . . . . . . 56
Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

What is dependency injection container in PHP? 57


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

What are design patterns in PHP? 57


The recommended major principles of programming . . . . . . . . . . 57
Types of design patterns . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Creational design patterns . . . . . . . . . . . . . . . . . . . . . . 58
Structural design patterns . . . . . . . . . . . . . . . . . . . . . . 58
Behavioral design patterns . . . . . . . . . . . . . . . . . . . . . . 58
Other design patterns . . . . . . . . . . . . . . . . . . . . . . . . 58
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

Abstract factory design pattern in PHP 59


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

Adapter design pattern in PHP 59


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

Bridge design pattern with PHP example 59


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

Builder design pattern in PHP 60

3
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

Chain of responsibility design pattern with PHP example 60


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

Command design pattern in PHP 61


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

Composite design pattern in PHP 61


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

Decorator design pattern with PHP example 61


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

Dependency injection design pattern in PHP 61


Types of Dependency Injection . . . . . . . . . . . . . . . . . . . . . . 64
Constructor injection . . . . . . . . . . . . . . . . . . . . . . . . . 64
Setter injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Interface injection . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Dependency injection container . . . . . . . . . . . . . . . . . . . . . . 66
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

Facade design pattern with PHP example 66


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

Flyweight design pattern in PHP 67


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Interpreter design pattern in PHP 67


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Iterator design pattern in PHP 67


PHP implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

Lazy loading design pattern in PHP 67


Lazy loading with closures . . . . . . . . . . . . . . . . . . . . . . . . . 69
PHP implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

Mediator design pattern with PHP example 71


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

Memento design pattern in PHP 71


UML diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

Mock object design pattern in PHP 71

4
Implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

Null object design pattern in PHP 72


PHP example of the null object pattern . . . . . . . . . . . . . . . . . 72
Open source PHP implementations . . . . . . . . . . . . . . . . . . . . 74
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

Object pool design pattern in PHP 75


PHP example of object pool . . . . . . . . . . . . . . . . . . . . . . . . 75
More practical examples . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Open source PHP implementations . . . . . . . . . . . . . . . . . . . . 77
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Observer design pattern in PHP 77


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Prototype design pattern in PHP 77


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Proxy design pattern in PHP 77


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Servant design pattern in PHP 78


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

Singleton design pattern in PHP 79


When to use the singleton pattern? . . . . . . . . . . . . . . . . . . . . 80
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

State design pattern in PHP 81


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

Strategy design pattern in PHP 81


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

Template method design pattern in PHP 81


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

Type tunnel design pattern in PHP 82


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

Visitor design pattern in PHP 82


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

What is an anti-pattern? 83
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

5
What is a database and how to access databases from PHP? 83
Application examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Database access from PHP . . . . . . . . . . . . . . . . . . . . . . . . 84
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

Why are mysql_* functions removed and what to do? 84


How to fix it? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
MySQL improved extension - MySQLi . . . . . . . . . . . . . . . . . . 86
Why is MySQL extension deprecated? . . . . . . . . . . . . . . . . . . 87
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

PDO vs. mysqli? 87


Database connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Databases support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Named parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Object mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

What is PDO? 91
Why PDO over others? . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Allow exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Retrieving data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Prepared statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Specify how to fetch . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
CRUD examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Insert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Update . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97

Database management systems vs. file systems? 97


Database management systems vs. file systems . . . . . . . . . . . . . 97
Common limitations of some file system based DBs . . . . . . . . . . . 98
Advantages of a DBMS . . . . . . . . . . . . . . . . . . . . . . . . . . 98
When is a DBMS not necessarily appropriate? . . . . . . . . . . . . . 98

MongoDB vs. MySQL 99


MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
NoSQL and MongoDB . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

What is ORM? 102


Design patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
When not to use ORM? . . . . . . . . . . . . . . . . . . . . . . . . . . 102

6
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

How to store files in a database? 103

How to secure PHP web applications and prevent attacks? 104


Checklist of PHP and web security issues . . . . . . . . . . . . . . . . 104
Cross site scripting (XSS) . . . . . . . . . . . . . . . . . . . . . . . . . 105
Injections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
SQL injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Directory traversal (path injection) . . . . . . . . . . . . . . . . . 105
Command injection . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Code injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Cross site request forgery (XSRF/CSRF) . . . . . . . . . . . . . . . . 106
Public files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Passwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Uploading files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Session hijacking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Remote file inclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
PHP configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Error reporting . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Exposing PHP version . . . . . . . . . . . . . . . . . . . . . . . . 108
Remote files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
open_basedir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Session settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Use HTTPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
What is next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

How to work with users’ passwords and how to securely hash pass-
words in PHP? 111
Right way of hashing passwords in PHP . . . . . . . . . . . . . . . . . 112
Password hashing in older PHP versions (5.5 and below) . . . . . . . . 114
Password hashing in open source projects . . . . . . . . . . . . . . . . 114
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

What is SQL injection and how to prevent it? 114


SQL injection example with PDO . . . . . . . . . . . . . . . . . . . . . 115
mysqli example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

How to securely upload files with PHP? 117


Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Directory traversal . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Rename uploaded files . . . . . . . . . . . . . . . . . . . . . . . . 118
Check file type . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Check file size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Storing uploads to private location . . . . . . . . . . . . . . . . . 119

7
Client side validation . . . . . . . . . . . . . . . . . . . . . . . . . 119
Full example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Server configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Apache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Nginx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

Configuration in PHP applications 121


What is configuration? . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
What should a configuration implementation cover? . . . . . . . . . . 122
Distribution (mandatory) . . . . . . . . . . . . . . . . . . . . . . 122
Validation and sanitization (mandatory) . . . . . . . . . . . . . . 122
Zero-Configuration (optional) . . . . . . . . . . . . . . . . . . . . 122
Caching (recommended) . . . . . . . . . . . . . . . . . . . . . . . 123
Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
PHP files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
YAML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
INI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
NEON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Types of configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Bad practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Singleton pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Misconception of configurations . . . . . . . . . . . . . . . . . . . 131
Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Environment variables . . . . . . . . . . . . . . . . . . . . . . . . 132
PHP dotenv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Git repositories . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Configuration stored in the database . . . . . . . . . . . . . . . . . . . 134
SQLite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
How to use configuration in PHP application? . . . . . . . . . . . . . . 135
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

How to protect and hide PHP source code? 140


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

How to install SSL certificate and enable HTTPS? 140


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

Encryption, hashing, encoding and obfuscation 141


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

8
What is a PHP framework and which one should I learn and use?141
Which framework should you learn? . . . . . . . . . . . . . . . . . . . 143
Component frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Full stack frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Micro-frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Other resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Related FAQs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

How to make your own PHP framework? 145


What knowledge you will need to create a decent framework? . . . . . 146
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

CakePHP framework 146


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

CodeIgniter framework 146


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

Laravel framework 147


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

Symfony framework 147


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

Yii framework 148


Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

Zend framework 148


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

Writing quality code and code analysis 149


PhpMetrics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

How to test PHP code? 151


Test driven development (aka TDD) . . . . . . . . . . . . . . . . . . . 151
Unit testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Functional testing . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Behavior driven development (aka BDD) . . . . . . . . . . . . . . . . 151
Testing spaghetti code . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Why testing code if the application works ok and is in production? . . 152
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152

Behavior driven development 152


StoryBDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152

9
SpecBDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153

How to debug PHP code? What is debugging? 154


Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Types of errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Syntax errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Fatal errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
var_dump/print_r . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Xdebug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
phdbg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Symfony VarDumper . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Zend Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
FirePHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

How to write standardized PHP code? 156


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

Where to Get Open Source PHP libraries, scripts and packages?157


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

What is Composer? 158


Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Files and folders in PHP project . . . . . . . . . . . . . . . . . . 158
composer.json . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Managing dependencies . . . . . . . . . . . . . . . . . . . . . . . 159
Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

What is CMS and which one should I use? 160


Open source CMSes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Content Management Framework . . . . . . . . . . . . . . . . . . . . . 162
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

Which eCommerce application should I use or which framework


to use for building eCommerce application? 162

How to work with Excel in PHP? 163


Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

Are there any image manipulation libraries in PHP? Which ones


are good? 164

10
How to add pagination? 165
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165

What is payment gateway? How to integrate and use payment


gateways in PHP? 165

How to work with PDF files in PHP? 165

PHP packages 166


Administration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Pagination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Payment gateways . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Excel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Bitcoin/Altcoin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Serialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Encryption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
MySQLi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
PDO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
PDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Sanitization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
MarkDown . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Geometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

What is API? 168


Useful tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Documenting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

What is REST? 169


What is the difference between REST and RESTful? . . . . . . . . . . 169
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

What is SOAP and how to use it in PHP? 170


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170

Which editor and IDE to choose for writing PHP code? 170
IDE vs editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
How to choose IDE/editor? . . . . . . . . . . . . . . . . . . . . . . . . 170
IDEs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Client side development . . . . . . . . . . . . . . . . . . . . . . . 172

Atom editor for PHP developers 172


IDE or editor? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

11
Atom installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Themes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Code style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Atom beautify . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Editorconfig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
PHP Integrator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
PHP Debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
PHP Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Minimap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Highlight Selected . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Atom Minify . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Todo Show . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Color Picker and Pigments . . . . . . . . . . . . . . . . . . . . . 181
Ctrl-dir-scroll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Project Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Emmet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Docblockr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
File Icons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Framework specific packages . . . . . . . . . . . . . . . . . . . . . 181
Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Shortcuts and useful features . . . . . . . . . . . . . . . . . . . . . . . 182
Caveats and final thoughts . . . . . . . . . . . . . . . . . . . . . . . . 182
Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Learning curve . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

What is GIT? 184


Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
macOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Commit messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Open source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187

Which are recommended libraries and resources to use with PHP?187

Nopaste list and services to share and run code online 188
What is a nopaste? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
List of nopaste services . . . . . . . . . . . . . . . . . . . . . . . . 188
Run and execute code online . . . . . . . . . . . . . . . . . . . . 188
Online editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Screenshot sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189

12
Vagrant tutorial 189
What is Vagrant? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Project setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
What is PuPHPet? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
How to save your changes on a box? . . . . . . . . . . . . . . . . . . . 191
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

Web assets (images, JavaScript, CSS files) 191


Content delivery network (CDN) . . . . . . . . . . . . . . . . . . . . . 192
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192

Performance benchmarks and load testing 192


Apache HTTP server benchmarking tool . . . . . . . . . . . . . . . . . 192
Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Siege . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
JMeter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Gatling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
HTTP keep-alive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193

What is PHP community? What are PHP user groups? 193


PHP UG concept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
PHP community . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Content management systems . . . . . . . . . . . . . . . . . . . . . . . 195
Drupal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Joomla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
WordPress . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
CakePHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
CodeIgniter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Symfony . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196

What are PHP conferences and where can I attend one? 196
Highlighted PHP conferences . . . . . . . . . . . . . . . . . . . . . . . 197

What is ElePHPant and why PHP uses elephants in some logo-


types? 198
Other reincarnations of ElePHPant . . . . . . . . . . . . . . . . . . . . 199
PHP Women’s purple ElePHPant: . . . . . . . . . . . . . . . . . 199
PHP Architect’s orange ElePHPant - Archie: . . . . . . . . . . . 201
Laravel’s ElePHPant . . . . . . . . . . . . . . . . . . . . . . . . . 201
AmsterdamPHP ElePHPant . . . . . . . . . . . . . . . . . . . . . 201
Golden Elephpant . . . . . . . . . . . . . . . . . . . . . . . . . . 204

13
PHP 7 ElePHPant . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Symfony ElePHPant . . . . . . . . . . . . . . . . . . . . . . . . . 204
TrueNorth PHP Woolly Mammoth . . . . . . . . . . . . . . . . . 204
PHP Classes ElePHPant . . . . . . . . . . . . . . . . . . . . . . . 204
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205

How to ask smart questions? 205


Research the problem . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Ask the right people . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Don’t ask to ask . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Ask everyone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Don’t ask when busy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Be clear . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Include purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Be patient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212

PHP podcasts 212


PHP related podcasts . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
PHP framework related podcasts . . . . . . . . . . . . . . . . . . . . . 213
General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213

How to fix undefined variable/index notice? 213


Why does this happen? . . . . . . . . . . . . . . . . . . . . . . . . . . 213
How to fix “Undefined variable”? . . . . . . . . . . . . . . . . . . . . . 213
How to fix “Undefined index”? . . . . . . . . . . . . . . . . . . . . . . 214
Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Null coalescing operator . . . . . . . . . . . . . . . . . . . . . . . . . . 214

How to detect browser in PHP? 214

Where to get PHP certification? 215


Other PHP certificates . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

What is web crawling and how to crawl websites with PHP? 216
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216

How to work with date and time in PHP? 216


Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Difference between dates with DateTime . . . . . . . . . . . . . . 216
Difference between dates with Carbon . . . . . . . . . . . . . . . 216
Comparing dates . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Time zone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Localization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Quirks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

14
How to deploy PHP application? 219
What does the deployment include? . . . . . . . . . . . . . . . . . . . 220
Quality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
Application life cycle management (ALM) . . . . . . . . . . . . . . . . 220
How to choose the right deployment strategy? . . . . . . . . . . . . . . 220
FTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Moving on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
GIT + SSH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Deployer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Fabric . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Jenkins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
Other deployment options . . . . . . . . . . . . . . . . . . . . . . . . . 223
Paid services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
PaaS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224

Can PHP be used for building desktop applications? 224


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224

How to send email with PHP? 225


mail() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
PHPMailer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Swift Mailer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
Zend Mail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227

How to show and handle errors in PHP? 227


Development environment . . . . . . . . . . . . . . . . . . . . . . . . . 228
Production environment . . . . . . . . . . . . . . . . . . . . . . . . . . 228
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228

How to detect face with PHP? 229

$_GET vs $_POST? 229


GET method: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
POST method: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
Raw POST data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230

How to fix Cannot modify header information - headers already


sent by… warning? 231
Which functions usually produce this? . . . . . . . . . . . . . . . . . . 231
Why this happens? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Checklist of possible causes and how to fix it . . . . . . . . . . . . . . 232

How to increase the upload file size in PHP? 232


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233

15
How to get client’s IP address in PHP? 233
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234

How to detect ISP with PHP? 234

Open source licenses 235


What is a license and why should you pick one for your project? . . . 235
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235

How to create Phar (PHP Archive)? 235


Packed php application archive . . . . . . . . . . . . . . . . . . . . . . 235

How to use PHP from the command-line? 236


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236

How to make readable, SEO friendly URLs in PHP? 236


How to achieve this? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Apache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Nginx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
How to process request in PHP? . . . . . . . . . . . . . . . . . . . . . 238
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238

What is the difference between a developer and programmer? 239

Can you suggest some projects I can make? 239


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

Regex - regular expressions in PHP 240


Brief history . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
Common regex usage in PHP . . . . . . . . . . . . . . . . . . . . . . . 240
Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
Replacing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
Common regex usage in JavaScript . . . . . . . . . . . . . . . . . . . . 241
Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
Replacing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
Caveats of regex in JavaScript . . . . . . . . . . . . . . . . . . . . 241
Basics of regex patterns . . . . . . . . . . . . . . . . . . . . . . . . . . 242
Sockets analogy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
Using regex for validation . . . . . . . . . . . . . . . . . . . . . . . . . 243
When not to use regex for validation? . . . . . . . . . . . . . . . 243
Regex validation . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Searching and replacing . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Replace words in the list with something . . . . . . . . . . . . . . 244
Swap two numbers . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Change date formatting . . . . . . . . . . . . . . . . . . . . . . . 245
Simple example of replacing URL with <a> tag . . . . . . . . . . 245
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246

16
What is web scraping and how to scrape data in PHP? 246
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247

How to take screenshot of a URL with PHP? 247


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247

Single vs double quotes in PHP 247


PHP Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
Single quoted strings . . . . . . . . . . . . . . . . . . . . . . . . . 247
Double quote strings . . . . . . . . . . . . . . . . . . . . . . . . . 248
Heredoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
Nowdoc (since PHP 5.3.0) . . . . . . . . . . . . . . . . . . . . . . 249
Credit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249

How to send SMS with PHP? 249


See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249

Which PHP template engine to use? 251

How to manage wildcard subdomains in PHP? 253

How to fix failed to open stream warning? 253


Why does this happen? . . . . . . . . . . . . . . . . . . . . . . . . . . 253
How to fix this? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
What if the included file is in a different subfolder then the including
file? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254

What is the difference between a core PHP and a vanilla/plain


PHP? 254
Core PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Vanilla or plain PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
See also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255

PHP best practices 255


Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
PHP setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
PHP version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
PHP extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Coding style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Coding standards . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Ternary operator . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
Composer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
Passwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258

17
Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
Secured configuration files . . . . . . . . . . . . . . . . . . . . . . 258
Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Development environment . . . . . . . . . . . . . . . . . . . . . . . . . 259

What is PHP? Where should I start?


PHP (which is a recursive backronym of “PHP: Hypertext Preprocessor”) is a
widely used, general purpose, open source scripting language for writing web
applications, dynamically generated pages and command line interface scripts.

Where to start?

If you want to learn PHP and web development as properly and as “right way” as
possible, it is very important to gain basic knowledge of mathematics, computer
science, programming in general and similar tech fields before learning PHP or
other languages.
PHP is located and best described by the official website PHP.net, with an up-
to-date and in-depth manual located here. Reading it is highly recommended
to get to know PHP in detail. As you read through the manual, your knowledge
will progress. You can start with the “Simple PHP Tutorial” to get PHP up
and running fast.
Use Google for the more obvious issues that you’re likely to find or ask on
forums.

Where to go next?

Another important part of being a developer is to constantly learn and keep


updated about new things either from PHP or development and programming
in general. Here are some recommended resources to stay up-to-date about PHP
and to learn more:
• PHP on Reddit - The latest news in the PHP world.
• PHP Weekly - Free, curated, once-a-week newsletter, featuring great PHP
articles, news and blog posts.
• SitePoint PHP - PHP tutorials and articles.

18
See also

Recommended, quality and modern guides, videos and tutorials for starting
with development and PHP in particular:
• Basics of programming for beginners
• Codecademy - Free course for learning to program in PHP; 4 hours.
• Codecourse - Free videos for learning PHP; 2.5 hours.
• CS50x - Harvard University’s introduction course to computer science.
• Devcasts - PHP video tutorials.
• Hacking with PHP - PHP book from beginning to advanced.
• Nomad PHP - What to learn first in PHP?; 16 minutes video.
• OverAPI PHP - PHP cheat sheet.
• PHP School - Interactive open source learning for PHP through command
line.
• PHP: The Right Way - An easy-to-read, quick reference for PHP best
practices, accepted coding standards, and links to authoritative tutorials
around the web.
• thenewboston - Free videos for learning PHP; 200 videos.
• w3clan PHP - Free PHP tutorials.
• Devscreencast - Free introduction to programming with PHP Course.

PHP evolution
Knowing something about PHP history and about who initially created the PHP
language and started the PHP project is interesting information that might help
inspire you for developing something of your own. It might also help you to
better understand the current state of PHP functionality.
PHP was initially written by Rasmus Lerdorf. It all started in 1994 when
Rasmus started working on the very first incarnation of PHP which was a simple
set of Common Gateway Interface (CGI) binaries written in the C programming
language.

See also

• PHP Evolution - Timeline with important milestones of PHP evolution.


• Wikipedia

19
How to install PHP? Which version of PHP to
use?
PHP installation might not be so obvious at first. Included here is a quick
overview of how to get PHP up and running fast.

PHP versions

Make sure to use the latest stable version PHP 7.1. Versions on some online
production servers can be few versions behind the latest PHP releases because
of hosting policies and backwards compatibility. Don’t let this stop you from
using the latest PHP with all its shiny new features.

PHP installation

You can download and use PHP binaries and sources for Windows and other
systems from the official site. Building PHP from source on your own has its
benefits in that you can configure your build according to your specific require-
ments. Refer to the PHP manual for learning how to build PHP from source.
PHP has a useful built-in web server for local development. Inside your project
folder you can run it from the command line:
$ php -S localhost:8000
Visit http://localhost:8000/index.php in your browser to access it.
To successfully develop and run PHP applications you will eventually need a
more advanced web server such as Apache or Nginx, a database such as MySQL
or MariaDB, and other useful tools such as Xdebug, Adminer, phpMyAdmin, etc.
Whether you’re using Windows, OS X or Linux, you can simplify installation
by using one of these all-in-one packages:
• AMPPS
• XAMPP
• Zend Server

Windows installation

Aside from the above, on Windows, you can also use one of the following useful
all-in-one packages:
• Easy PHP
• WPN XM

20
OS X

By default, OS X includes a slightly outdated PHP. To install and use the latest
PHP on OS X, aside from by using one of the aforementioned packages, you
can also use one of the following solutions:
• Homebrew PHP repository for Homebrew package manager.
• Liip’s PHP binary package.
• MacPorts - Package management system provided by an open source com-
munity initiative.
• MAMP - All-in-one package for OS X (and Windows).

Linux installation

Linux and Unix based operating systems are a bit more complex and diverse.
Learning to use these environments is recommended for developers. After all,
there’s a high chance that your web application will be hosted on such servers.
PHP installation can be done with package managers, that distribution uses
(apt-get, pacman, zypper or yum, with its successor dnf).
A simplified example of apt usage for Debian based distributions (Debian,
Ubuntu…):
$ sudo apt-get install php
and yum (or newer dnf) for Fedora based distributions (Fedora, RHEL, Cen-
tOS…):
$ sudo dnf install php
Keep in mind that there are many other packages such as php-curl,
lamp-server, php-mysql and others, to be explored with your distribution.

Third-party Linux repositories

Most of the time the default PHP version provided by the distribution will be a
few versions behind the latest stable release from PHP.net. This is where some
useful third-party repositories can come in handy:
• deb.sury.org - For Debian and Ubuntu.
• REMI repository - For Fedora, CentOS and RHEL.
• Webtatic - For Fedora, CentOS and RHEL.

Virtualization

A more advanced and recommended way of professional PHP development nowa-


days is by using virtualization software such as Virtual Box, Vagrant, and

21
Docker. These help you reduce friction between development and production
environments. With virtual environments, you can make your development
(software versions, configuration…) the same as what your production is.

Docker

When using Docker, check the PHP images at Docker Hub.

Why choose PHP?

PHP compared to other programming languages

A completely normal question to ask yourself when starting a project is which


technologies to use.
Some of the strengths of PHP:
• Good speed and performance.
• Simplicity and the ability to develop complex applications.
• Very vibrant, large, and diverse community.
• Active, updated, and detailed manual.
• A wide selection of out-of-the-box, popular, and production ready open
source solutions such as content management and e-commerce systems,
CRMs, frameworks, and components and libraries for building applica-
tions from scratch.
• PHP is used by 82.1% of all the websites whose server-side platform could
be measured.

See also

If you’re still not convinced just yet, please also check some of these other
resources on this topic:
• Why choose PHP over alternatives - Why should a developer choose PHP
for new projects, rather than an alternative language?

Which books are recommended for learning


PHP?
There are many books available for learning PHP, but they can quickly become
outdated in a short period of time. Included here is a quick list of PHP books
you should look into when learning PHP or extending your knowledge. Also keep

22
in mind that writing a very good programming book can take several thousand
hours, so supporting their authors is nice way of saying thank you.

Free PHP books

• Official PHP manual - Offical PHP manual is also available for offline
usage.
• PHP: The Right Way - An easy to read, quick reference for PHP best
practices, accepted coding standards, and links to authoritative PHP tu-
torials around the web. “PHP: The Right Way” is also available as a PDF
book.
• PHP 5 Power Programming
• PHP Best Practices - A short, practical guide for common and confusing
PHP tasks.
• PHP Essentials
• PHP Internals Book
• PHP Pandas - Aims to teach everyone how to be a web developer.
• PHP Programming
• PHP Security Guide
• Practical PHP Programming
• Practical PHP Testing
• Survive The Deep End: PHP Security - PHP Security
• Wikibooks PHP Programming - A PHP programming book on Wikibooks.
• Using Libsodium in PHP Projects - A guide to using the libsodium PHP
extension for modern, secure, and fast cryptography.

Paid PHP books

• Build APIs You Won’t Hate


• Building Secure PHP Apps
• Iterating PHP Iterators
• Learnable: PHP Master: Write Cutting-edge Code
• Modern PHP: New Features and Good Practices
• Modernizing Legacy Applications In PHP
• PHP Objects, Patterns, and Practice
• Practical Design Patterns
• Securing PHP: Core Concepts
• Securing PHP: Usual Suspects
• Scaling PHP
• Signaling PHP
• The Grumpy Programmer’s Guide To Building Testable PHP Applications
• Typed PHP
• O’Reilly: PHP Books

23
Which hosting service should I use for PHP? Are
there any free hosting providers?
In order for a web application to be able to run on the web (production envi-
ronment), you usually choose a hosting service provider with a web server.

Types of web hosting

Shared hosting

A shared web hosting service or virtual hosting service is a service where many
websites are hosted on the same webserver, and the server’s resources (RAM,
disk, and processor) are shared among the users. PHP settings and installed
extensions are usually the same for all websites. It might be a good option if
you want to get started quickly and painlessly, but still leave the maintaining
and server upgrading to your preferred hosting service.

VPS

A VPS (virtual private server) is a step up in terms of hosting services. It can


be a bit more pricey than shared hosting, but no other user shares your package.
A VPS can get a dedicated amount of RAM, disk, and processor speed, so your
application is already a step forward in gaining more freedom in its settings and
customizations.

Dedicated server

A dedicated server means an entire server machine, dedicated for your needs.
More resources and disk quota is available for you when choosing to use a ded-
icated server. The price can be high, but flexibility and customization is at its
best. Choose this option if you’re an advanced user with system administration
knowledge.

Collocation

Collocated hosting means that you bring your own hardware to your data center
service provider, and they plug it onto their high speed and availability network.

Cloud hosting

This is latest trend in web hosting services with greater flexibility.

24
Free PHP hosting

One of the most frequently asked questions is whether there any good, free
providers for hosting PHP applications.
In short, yes, there are, but keep in mind that sooner or later you’ll meet
limitations with this approach. Almost nothing is completely free, and the
same is true for web hosting.
Some of the limitations to be aware of:
• Traffic quota limit.
• Server resources quota limit.
• PHP extensions and functionality limitations.
• Forcibly injected advertising.
A quick list of some free hosting providers to check out:
• Amazon AWS Free Tier
• Heroku
• Zeit now
• …
Do yourself and your application’s audience a favor and invest a bit into your
hosting infrastructure. Stability and availability of your application will depend
on a lot on this.

See also

• Compare hosting online


• PHP Versions - Learn which versions of PHP are available on different
web hosting providers, so that you can make informed decisions.

PHP basics
1. PHP in a nutshell
2. Basic syntax
1. Hello world
2. Operators
• Arithmetic operators
• Comparison operators
• Logical operators
• Assignment operators
3. Declarations
4. Functions
• Anonymous functions (closures)

25
• Variadic functions
5. Control structures
• If
• Loops
• Switch
6. Arrays
• Operations on arrays
7. Built in types
3. Errors
1. PHP Errors
2. What is next?
This tutorial will show you basic PHP syntax and its features. If you’re new to
PHP, read the most basic PHP tutorial to get started as quickly and painlessly
as possible. For becoming a modern PHP developer, read and follow PHP: The
Right Way. Seriously.

PHP in a nutshell

• Scripting language
• Procedural and object oriented language
• Dynamically (weakly) typed
• Syntax similar to C, C++, C#, Java and Perl
• Imperative language
• PHP has closures

Basic syntax

Hello world

File hello.php:
<?php

echo 'Hello, world.';


$ php hello.php

Operators

Arithmetic operators

Operator Name Result


-$a negation Opposite of $a.

26
Operator Name Result
$a + $b addition Sum of $a and $b.
$a - $b Subtraction Difference of $a and $b.
$a * $b Multiplication Product of $a and $b.
$a / $b division Quotient of $a and $b.
$a % $b modulus Remainder of $a divided by $b.
$a ** $b Exponentiation Result of raising $a to the $b’th power.

Comparison operators

Operator Name Result


$a == Equal TRUE if $a
$b is equal to
$b after
type
juggling.
$a === Identical
TRUE if $a
$b is equal to
$b, and
they are of
the same
type.
$a != Not TRUE if $a
$b equal is not equal
to $b after
type
juggling.
$a <> Not TRUE if $a
$b equal is not equal
to $b after
type
juggling.
$a !== Not TRUE if $a
$b identicalis not equal
to $b, or
they are
not of the
same type.
$a < $b Less TRUE if $a
than is strictly
less than
$b.

27
Operator Name Result
$a > $b GreaterTRUE if $a
than is strictly
greater
than $b.
$a <= Less TRUE if $a
$b than is less than
or or equal to
equal $b.
to
$a >= GreaterTRUE if $a
$b than is greater
or than or
equal equal to $b.
to

Logical operators

Operator Name Result


$a and $b And TRUE if both $a and $b are TRUE.
$a or $b Or TRUE if either $a or $b is TRUE.
$a xor $b Xor TRUE if either $a or $b is TRUE, but not both.
! $a Not TRUE if $a is not TRUE.
$a && $b And TRUE if both $a and $b are TRUE.
$a || $b Or TRUE if either $a or $b is TRUE.

Assignment operators

Operator Description
= Set a value to variable
+= Addition of numeric value to variable
.= Add string to variable

Declarations

• $i = 1; - assign value to variable


• define('FOO', 'something'); - define a constant

28
Functions

// A simple function
function functionName() {}

// A function with parameters


function functionName($param1, $param2) {}

Anonymous functions (closures)


<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// outputs helloWorld

// Anonymous function variable assignment example


$greet = function($name) {
printf("Hello %s\r\n", $name);
};
$greet('World');

// Inherit
$message = 'hello';

// Without "use" keyword


$example = function () {
var_dump($message);
};
echo $example();

// Inherit $message
$example = function () use ($message) {
var_dump($message);
};
echo $example();

Variadic functions
<?php
function sum(...$nums)
{
return array_sum($nums);
}

29
Control structures

If
if $x > 0 {
return $x;
} else {
return -$x;
}

Loops
// for
for ($i = 1; $i<10; $i++) {}

// while
while ($i < 10) {}

// do while
$i = 0;
do {
echo $i;
} while ($i > 0);

// foreach
foreach ($array as $key => $value) {}

Switch
// switch statement
switch ($operatingSystem) {
case 'darwin':
echo 'Mac OS Hipster';
break;
case 'linux':
echo 'Linux Geek';
break;
default:
// Windows, BSD, ...
echo 'Other';
}

30
Arrays

$array = [
"foo" => "bar",
"bar" => "foo",
];

Operations on arrays

Operator Name Result


$a + $b Union Union
of $a
and
$b.
$a == EqualityTRUE
$b if $a
and $b
have
the
same
key/value
pairs.
$a === IdentityTRUE
$b if $a
and $b
have
the
same
key/value
pairs
in the
same
order
and of
the
same
types.
$a != Inequality
TRUE
$b if $a is
not
equal
to $b.

31
Operator Name Result
$a <> Inequality
TRUE
$b if $a is
not
equal
to $b.
$a !== Non- TRUE
$b identityif $a is
not
identi-
cal to
$b.

Built-in types

Type
boolean
integer
float
string
array
object
resource
NULL

Errors

PHP errors

<?php
// Turn off all error reporting
error_reporting(0);

// Report simple running errors


error_reporting(E_ERROR | E_WARNING | E_PARSE);

// Reporting E_NOTICE can be good too (to report uninitialized


// variables or catch variable name misspellings ...)
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);

// Report all errors except E_NOTICE


error_reporting(E_ALL & ~E_NOTICE);

32
// Report all PHP errors (see changelog)
error_reporting(E_ALL);

// Report all PHP errors


error_reporting(-1);

// Same as error_reporting(E_ALL);
ini_set('error_reporting', E_ALL);

Exceptions

function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}

try {
echo inverse(5) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "This is always executed.\n";
}

What is next?

Use php.net. It has a great and detailed manual for your PHP adventures.

PHP 7
PHP 7 is the next major version of the PHP language. You really should check
it out and upgrade.

Why PHP 7 and not PHP 6?

Choosing the version 7 (instead of 6) was chosen because a lot of existing books
were mentioning PHP 6 long before the development of the next major version
after PHP 5 started. Andi Gutmans said “We’re going to skip version 6 because

33
Figure 1: PHP 7

years ago, we had plans for a 6 but those plans were very different from what
we’re doing now,” so the name PHP 7 was chosen.

Major changes

Most important changes from PHP 5:


• Performance improvements - PHP 7 is significantly faster than previous
versions.
• Uniform Variable Syntax
• Exceptions in the engine
• Scalar type declarations
• Combined comparison (spaceship) operator
• Easy user-land CSPRNG
• Null coalescing operator
• Removed deprecated functionality from PHP 5
Be sure to read more about the changes in the migration chapter of PHP manual.

Uniform variable syntax

Thanks to AST (Abstract Syntax Tree) implemented in PHP7 now you can
write expressions in the more predictable ways.

Following examples are not possible in PHP5

Chained function calls

34
$obj->someMethod()()()()();

Call a function by name returned from arbitrary expression


$var = 'Hello World!';
echo (is_string($var) ? 'strlen' : 'count')($var);

Call a callable created from array literal


echo [new ArrayObject($_SERVER), 'count']();
With uniform variable syntax, you can now do more operations on expressions.

Exceptions in the engine

In previous versions you couldn’t catch fatal errors. Now you can do this:
<?php

function doSomething($obj)
{
$obj->nope();
}

try {
doSomething(null)
} catch (\Error $e) {
echo "Error: {$e->getMessage()}\n";
}

// Error: Call to a member function method() on a non-object

Scalar type declarations

Now you can enforce parameter types as strings (string), integers (int), floating-
point numbers (float), and booleans (bool). Type declarations (previously
known as type hints) in PHP 5 were class names, interfaces, array and callable.
<?php

// Coercive mode
function sum (int ...$numbers)
{
return array_sum($numbers);
}

35
var_dump(sum(2, '3', 4.1)); // outputs 9
Besides coercive mode there is also strict mode which can be enabled per file
basis with:
<?php

declare(strict_types=1);
Read more about type declarations in the PHP manual.

Combined comparison (spaceship) operator

The spaceship operator is used for three-way comparison of two expressions. It


returns:
• 1 (if the left-hand operand is greater than the right-hand operand)
• 0 (if both operands are equal)
• -1 (if the right-hand operand is greater than the left-hand operand)
Example of spaceship operator where you need to sort multidimensional array
To do this, you can use usort() with comparison function:
<?php

$items = [
['title' => 'Mouse'],
['title' => 'Computer'],
['title' => 'LCD Screen'],
];

// sort items by title


usort($items, function ($a, $b) {
return $a['title'] <=> $b['title'];
});

Easy user-land CSPRNG

PHP 7 has two new functions random_bytes() and random_int() for generat-
ing cryptographically secure integers and strings in a cross platform way.
Before PHP 7 you had to use the generator on the platform. For example,
CryptGenRandom on Windows and /dev/urandom on Linux. If you’re building
modules that must work on all platforms, this might be an issue. In PHP 7 you
can simply use the built-in generator.

36
Null coalescing operator

It turned out that often you needed to use ternary operator with isset() func-
tion.
An example where you need to check if the GET data has been sent and set the
$username based on that. In PHP 5 you could do something like this:
<?php
$user = isset($_GET['user']) ? $_GET['user'] : 'Guest';
Now you can simplify this a lot:
<?php
$user = $_GET['user'] ?? 'Guest';

See also

Other resources and tutorials to get to know and use PHP 7:


• Rasmus Lerdorf’s PHP 7 development box - Debian Vagrant box with
PHP 7 installed.
• PHP 7 Docker container - Docker container with PHP 7.
• PHP 7 logo - PHP 7 logo by Vincent Pontier and Peter Cowburn.
• php7cc - PHP 7 Compatibility Checker.
• Reading:
– Getting ready for PHP 7
– PHP 7 Reference - An overview of the features, changes, and back-
ward compatibility breakages in PHP 7.
– PHP 7 tutorial - Interactive simple and efficient tutorial presenting
all the important changes and backwards incompatibilities.

PHP versions usage


Supported PHP versions provides some insights on which version you should
pick for your project.
Currently, the recommended version of PHP to use is the latest PHP 7, but the
statistic of PHP version usage on servers is kind of shocking.
Thanks to the research of PHP version usage, we have some data to work with.
The majority of PHP servers still have PHP 5.3 installed, and old versions of
PHP 5.2, although less so, are still also used.
PHP 5.3 reached EoL (End of Life) in August 2014, and PHP 5.5 reached EoL
(End of Life) in July 2016. For more information about unsupported EoL PHP
versions, visit PHP.net unsupported branches.

37
Figure 2: PHP version usage, october 2014

PHP 5.6.0 currently has active support, but that will expire in December 2017.

PHP version requirements in open source

Having wide availability of the software is important for open source projects.
Increasing minimum version requirement is in many cases a delicate issue, but
more and more projects are requiring more or less the latest versions already.
Enforcing later versions is a good thing to encourage users to upgrade the PHP
used on their servers.

Why is upgrading PHP important?

• New great features.


• Better performance (PHP 7 has huge performance improvements over pre-
vious versions).
• Better coding possibilities.
• Future preparation for less painful upgrades of your application.
• Security.
• Without upgrading, open source libraries are forced to support older ver-
sions due to there being many older versions still in use (wide availability

38
of developer’s code is important).

What to do?

• Ask for better environment: A server with the latest stable PHP version
installed and operable.
• Upgrade to the latest PHP version and refactor old code.
• Push the miniminum version of PHP in composer.json files to newer
PHP versions.
• Create a maintainability strategy for your projects to upgrade server soft-
ware together with PHP on a regular basis.

See also

• PHP minimal version in Symfony 3.0 - Symfony 3.0 roadmap and minimal
PHP version.
• Jordi Boggiano - PHP versions stats on packagist.org.
• schmengler-se.de - Dropping PHP 5.3 support.
• ircmaxell’s blog post on install statistics - PHP install statistics.

Why does PHP use a dollar sign $ to prefix vari-


ables?
Rasmus Lerdorf, the father of the PHP language, explains the $ sign as an
ability to insert variables inside literal string values (interpolation), so that the
variables are distinguished from the rest of the string. A dollar sign in front of
variables in PHP is inspired by Perl which greatly influenced PHP during its
early years.
Many other programming languages also use a dollar sign in their syntax. This
symbol is called “sigil” and simplifies interpolation.
Names not prefixed by $ are considered constants, functions, class names, etc.
Sigil usage simplifies the variable interpolation into strings:
<?php

$name = "World";
echo "Hello, $name";
Where as in languages without sigil usage (for example, Python), you must
either concatenate strings:

39
name = "World"
print "Hello, " + name
or use special interpolation syntax if the language provides it. For example,
Ruby:
name = "World"
puts "Hello #{name}"
Many people used to other languages might find the sigil usage odd, but you
can get used to it in no time and discover the its benefits.

See also

• PHP Manual: Strings

What is object oriented programming (OOP)?


Object oriented programming (OOP) is a programming paradigm with objects
and classes. Objects are usually instances of classes which have methods (func-
tions defined inside a class) and properties (variables defined in class as descrip-
tions of that class).
PHP has always been an object oriented programming language. PHP 5 intro-
duced a full object model. As newer versions emerged over time, PHP reached
the point of being almost a fully object oriented language. Many still consider
PHP object oriented capabilities as not fully object oriented, but it’s a matter
of a perspective and coding style as well.
Many developers don’t find the concept of the object oriented paradigm to
be useful, because it seems scary, or because they don’t yet understand the
practical benefits of it, but for more advanced scripts, OOP is essential part of
PHP development.

Object oriented concepts

Before we get into details, let’s define some important OOP terms.
• Class: This is a programmer-defined datatype, which includes local func-
tions and local data. You can think of a class as a template for making
many instances of the same kind (or class) of object.
• Object: An individual instance of the data structure defined by a class.
You define a class once and then make many objects that belong to it.
Objects are also known as instances.

40
• Member variable: These are the variables defined inside a class. This
data will be invisible to the outside of the class and can be accessed via
member functions. These variables are called attributes of the object once
it’s created.
• Member function: These are the functions defined inside a class and
are used to access object data.
• Inheritance: When a class is defined by inheriting existing function of a
parent class, it is called inheritance. Here, a child class inherits some or
all member functions and variables of its parent class.
• Parent class: A class that is inherited from by another class, also referred
to as a base class or super class.
• Child class: A class inherits from another class (the parent class), also
referred to as a subclass or derived class.
• Polymorphism: This is an object oriented concept where the same func-
tion can be used for different purposes. For example, the name of a func-
tion remaining the same but taking a different number of arguments and
performing a different task.
• Overloading: A type of polymorphism in which some or all operators
have different implementations depending on the types of their arguments.
Similarly, functions can also be overloaded with different implementations.
• Data abstraction: Any representation of data in which the implementa-
tion details are hidden (abstracted).
• Encapsulation: Refers to a concept whereby data is encapsulated to-
gether with member functions to form an object.
• Constructor: Refers to a special type of function to be called automati-
cally whenever an object is formed from a class.
• Destructor: Refers to a special type of function to be called automati-
cally whenever an object is deleted or goes out of scope.

Defining classes

General form for defining a new class in PHP:


<?php

class PhpClass
{
public $var1;
public $var2 = 'string value';

41
public function myfunction($arg1, $arg2)
{
// ...
}

// ...
}
Explanations of keywords used in the above class definition:
• Keyword class, followed by the name of the class, PhpClass.
• Opening and closing braces {}, which include any number of properties
and methods.
• Property declaration can start with the keyword public, which is then
followed by a conventional $variableName. It may also have an initial
assignment of values.
• Method definitions look much like stand-alone PHP functions but are local
to the class and can used to set and access object data.

Example

Here is an example which defines a class Book:


<?php

class Book
{
public $price;
public $title;

public function setPrice($price)


{
$this->price = $price;
}

public function getPrice()


{
return $this->price;
}

public function setTitle($title)


{
$this->title = $title;
}

public function getTitle()

42
{
return $this->title;
}
}
Special variable $this refers to the current object (i.e. itself).

Creating class instances

Once you define your class, you can create as many objects as you like of that
class type. With the new keyword, you create an object (a class instance):
$physics = new Book();
$maths = new Book();
$chemistry = new Book();
Here we have created three new objects which are independent of each other.

Calling class methods

Let’s check how to call methods and process class properties. After creating
your objects, you will be able to call class methods related to that object. One
class method will be able to process class properties of the related object only.
The following example shows how to set titles and prices for these three books
by calling class methods.
$physics->setTitle('Physics for High School');
$physics->setPrice(10);

$maths->setTitle('Algebra');
$maths->setPrice(7);

$chemistry->setTitle('Advanced Chemistry');
$chemistry->setPrice(15);
Now you call another methods to get the values from above example:
echo $physics->getTitle();
echo $physics->getPrice();

echo $maths->getTitle();
echo $maths->getPrice();

echo $chemistry->getTitle();
echo $chemistry->getPrice();
This will produce the following result:

43
Physics for High School
10
Algebra
7
Advanced Chemistry
15

Constructor methods

Constructor method __construct() is a special type of method which is called


automatically whenever an object is created.
Constructor methods accept as many arguments as you define in the class defi-
nition.
The following example will create one constructor for Books class and it will
initialize the price and title for the book at the time of object creation.
public function __construct($title, $price)
{
$this->price = $price;
$this->title = $title;
}
With the above __construct() we don’t need to call set methods separately
to set the price and title. We can initialize these two member variables at the
time of object creation only:
$physics = new Book('Physics for High School', 10);
$maths = new Book('Advanced Chemistry', 15);
$chemistry = new Book('Algebra', 7);

/* Get those set values */


echo $physics->getTitle();
echo $physics->getPrice();

echo $maths->getTitle();
echo $maths->getPrice();

echo $chemistry->getTitle();
echo $chemistry->getPrice();
The above will produce the same result as in the previous example.

44
Destructor

Like with the constructor method, you can also define a destructor by using
the special method __destruct(). A destructor is called automatically as soon
as there are no more references to a particular object or during the shutdown
sequence. Within a destructor you can release all resources.
From the Books class example above, let’s add the following destructor.
public function __destruct()
{
echo "A book ({$this->title}) is destroyed.\n";
}
$physics = new Book('Physics for High School', 10);
$maths = new Book('Advanced Chemistry', 15);
$chemistry = new Book('Algebra', 7);
$mathsCopy = $maths;

unset($physics, $maths, $chemistry);

echo "Program is about to exit.\n";

Output

A book (Physics for High School) is destroyed.


A book (Algebra) is destroyed.
Program is about to exit.
A book (Advanced Chemistry) is destroyed.
You can see that Advanced Chemistry was shown after the text Program is
about to exit., even though $maths was previously unset. That was because
there was still another reference to the object ($mathsCopy).

Inheritance

PHP class definitions can optionally inherit from a parent class definition by
using the extends keyword:
class Child extends Parent
{
// Definition body
}
The effect of inheritance is that the child class (or subclass, or derived class)
has the following characteristics:

45
• It automatically has all the member variable declarations of the parent
class.
• It automatically has all the same member functions as the parent, which
will work the same way as those functions do in the parent by default.
The following example inherits the Book class and adds additional functionality
compared to the parent class.
class Novel extends Book
{
public $publisher;

public function setPublisher($publisher)


{
$this->publisher = $publisher;
}

public function getPublisher()


{
return $this->publisher;
}
}
Class Novel adds two additional methods to the parent class.

Methods overriding

Methods defined in child classes override methods with the same name in parent
classes. In a child class, we can modify the definition of a method inherited from
parent class.
In the following example, the getPrice() method is overriden to return a price
number with currency.
public function getPrice()
{
return $this->price . " EUR";
}

Public members

Unless you specify otherwise, properties and methods of a class are public by
default. This means that they may be accessed in three possible situations:
• From outside the class in which it is declared.
• From within the class in which it is declared.
• From within another class that implements the class in which it is declared.

46
Until now, we have seen all members as public members. If you wish to limit
the accessibility of the members of a class, you define class members as private
or protected.

Private members

By setting a member as private, you limit its accessibility to only the class
where it is defined. The private member can not be used in inherited classes
nor outside the class.
A class member can be made private by using the private keyword in front of
the member.
class Car
{
private $model = 'skoda';
$driver = 'SRK';

public function __construct()


{
// Statements here run every time
// an instance of the class
// is created.
}

public function myPublicFunction()


{
return("I'm visible!");
}

private function myPrivateFunction()


{
return("I'm not visible outside!");
}
}
When the class Car is inherited by another class with the extends keyword, the
method myPublicFunction() and the property $driver will be visible. The ex-
tended class will not have any awareness of nor access to myPrivateFunction()
or $model, because they are declared as private.

Protected members

A protected property or method is accessible in the class in which it is declared


and in inherited classes. Protected members are not available outside of those

47
two contexts. A class member can be made protected by using the protected
keyword in front of the member.
Here is a different version of the class Car:
class Car
{
protected $car = 'skoda';
$driver = 'SRK';

public function __construct()


{
// Statements here run every time
// an instance of the class
// is created.
}

public function myPublicFunction()


{
return("I'm visible!");
}

protected function myPrivateFunction()


{
return("I'm visible in child class!");
}
}

Interfaces

Interfaces provide common method names to implementors. Different imple-


mentors can implement those interfaces according to their requirements. You
could say that interfaces are skeletons which are implemented by developers.
Let’s define an interface:
interface Mail
{
public function sendMail();
}
The class then implements the above interface like this:
class Report implements Mail
{
public function sendMail()
{
// Code that sends an email.

48
}
}

Class constants

A class constant is an immutable value. Once you declare a constant, it can not
be changed:
class MyClass
{
const MARGIN = 1.7;

public function __construct($argument)


{
// Statements here run every time
// an instance of the class
// is created.
}
}
In this class, MARGIN is a constant. It is declared with the keyword const and it
can not be changed under any circumstances to anything other than the default
value 1.7. Unlike variable names, constant names doesn’t have a leading $.

The static keyword

Declaring class members or methods as static makes them accessible without the
need for class instantiation. A member declared as static can not be accessed
with an instantiated class object (although a static method can).
Try out the following example:
class Foo
{
public static $myStatic = 'foo';

public function staticValue()


{
return self::$myStatic;
}
}

print Foo::$myStatic . "\n";


$foo = new Foo();
print $foo->staticValue() . "\n";

49
The final keyword

The final keyword prevents child classes from overriding a method by adding
final to the definition. If the class itself is being defined final then it can not
be extended.
The following example results in “Fatal error: can not override final method
BaseClass::moreTesting()”
class BaseClass
{
public function test()
{
echo "BaseClass::test() called<br>";
}

final public function moreTesting()


{
echo "BaseClass::moreTesting() called<br>";
}
}

class ChildClass extends BaseClass


{
public function moreTesting()
{
echo "ChildClass::moreTesting() called<br>";
}
}

Calling parent constructors

Instead of writing a new constructor for the subclass, you can call the parent’s
constructor explicitly and then do whatever is necessary in addition for instan-
tiation of the subclass. Here’s a simple example:
class Person
{
private $firstName;
private $lastName;

public function __construct($firstName, $lastName)


{
$this->firstName = $firstName;
$this->lastName = $lastName;
}

50
public function getFullName()
{
return $this->firstName.' '.$this->lastName;
}
}

class Student extends Person


{
private $title;

public function __construct($title, $firstName, $lastName)


{
parent::__construct($firstName, $lastName);
$this->title = $title;
}

public function getFullName()


{
return $this->title.' '.parent::getFullName();
}
}
In this example, we have a parent class Person, which has a constructor with
two arguments, and a subclass Student, which has a constructor with three
arguments. The constructor of Student calls the parent constructor with
parent::__construct() and then sets an additional field. Class Student also
overrides the getFullName() method.

See also

• PHP.net: Classes and Objects - A must read PHP OOP manual chapter.
• Learn OOP in PHP - A collection of resources to learn object-oriented
programming and related concepts for PHP developers.
• When to declare classes final

Abstract classes in PHP


An abstract class is one that can be inherited, but not instantiated. It is declared
with the keyword abstract:
<?php

abstract class MyAbstractClass

51
{
public function myImplementedMethod()
{
echo 'Hello World!';
}
}
Abstract classes can also contain abstract methods. Abstract methods are meth-
ods without body (implementation).
<?php

abstract class MyAbstractClass


{
public function myImplementedMethod()
{
echo 'Hello World!';
}

// Body can be simply omitted.


abstract function myAbstractMethod();
}
When inheriting from an abstract class, all methods marked abstract in the
parent’s class declaration must be defined by the child. Additionally, these
methods must be defined with the same (or a less restricted) visibility.
<?php

abstract class MyAbstractClass


{
public function myImplementedMethod()
{
echo 'Hello World!';
}

// Although this method was declared protected,


abstract protected function myAbstractMethod();
}

class MyConcreteClass extends MyAbstractClass


{
// but it can be public in child class.
public function myAbstractMethod()
{
echo "I'm now implemented!";
}
}

52
It is not legal to have abstract function definitions inside a non-abstract class.
Any class that contains at least one abstract method, must be declared abstract.
In PHP, abstract classes cannot be declared final.

See also

Other useful resources to check out:


• PHP Manual - Class abstraction chapter in the PHP manual.

What are iterators in PHP and how to use them?


An iterator is an object that enables a programmer to traverse a container.
Various types of iterators are often provided via a container’s interface.
// Create a DirectoryIterator to list all files in current directory.
$it = new DirectoryIterator('./');
foreach ($it as $file) {
// Excludes . and .. entries.
if (!$file->isDot()) {
echo $file->getFilename(), "\n";
}
}
All iterator objects in PHP must implement either the Iterator or the
IteratorAggregate interface. Iterator and IteratorAggregate both extend
the Traversable interface which is an abstract interface that can not be
implemented directly by any classes. Traversable itself has no methods
defined. The sole purpose of Traversable is to be used as dependency.
/*
* This function accepts both Iterator and IteratorAggregate as its parameter.
*/
function giveMeTraversable(Traversable $it)
{
// ...
}
Some built-in functions also require Traversable as parameters. For example:
iterator_count(), iterator_to_array().
Objects implementing Iterator act as the iterator itself, while objects imple-
menting IteratorAggregate act as a provider of Iterator. Both can be used
as an iterator.
The Iterator interface has 5 methods defined.

53
interface Iterator extends Traversable
{
public function current();
public function key();
public function next();
public function rewind();
public function valid();
}
While the IteratorAggregate interface has only 1 method.
interface IteratorAggregate extends Traversable
{
public function getIterator();
}

Using the Iterator interface

class IntegerRangeIterator implements Iterator


{
private $start;
private $end;
private $key;
private $value;

public function __construct($start, $end)


{
$this->start = (int)$start;
$this->end = (int)$end;
$this->rewind();
}

public function current()


{
return $this->value;
}

public function key()


{
return $this->key;
}

public function next()


{
if (!$this->valid()) {
return;

54
}
if ($this->value === $this->end) {
$this->value = null;
return;
}
if ($this->start < $this->end) {
$this->value++;
} else {
$this->value--;
}
$this->key++;
}

public function rewind()


{
$this->value = $this->start;
$this->key = 0;
}

public function valid()


{
return !is_null($this->value);
}
}

$it = new IntegerRangeIterator(10, 1);


foreach ($it as $key => $value) {
echo $key, ':', $value, "\n";
}

Output

0:10
1:9
2:8
3:7
4:6
5:5
6:4
7:3
8:2
9:1

55
Using IteratorAggregate interface

<?php
class IntegerRangeIterator implements IteratorAggregate
{
private $start;
private $end;

public function __construct($start, $end)


{
$this->start = (int)$start;
$this->end = (int)$end;
}

public function getIterator()


{
return new ArrayIterator(range($this->start, $this->end));
}
}

$it = new IntegerRangeIterator(1, 10);


foreach ($it as $key => $value) {
echo $key, ':', $value, "\n";
}

Output

0:1
1:2
2:3
3:4
4:5
5:6
6:7
7:8
8:9
9:10

People often forget about the underused, built-in iterators in PHP’s standard
PHP library.

56
Resources

• PHP manual - The Iterator interface chapter in the PHP Manual.

What is dependency injection container in PHP?


To better understand dependency injection container, the dependency injection
design pattern is a prerequisite.
Dependency injection container is very useful and recommended way of man-
aging class dependencies. It is a utility which helps you to implement the
dependency injection pattern in your application.
Dependency injection container is a combination of container design pattern,
factory pattern and (optionally) flyweight pattern when utilizing objects as ser-
vice descriptors. General implementations of dependency injection container
are also inspecting components (utilizing reflection).

See also

• PHP-DI - Dependency injection container PHP library.


• Pimple - A simple PHP dependency injection container.
• Do you need a Dependency Injection Container?
• Symfony Dependency Injection Component
• Laravel Service Container
• Aura.DI
• Dependency Injection: An analogy

What are design patterns in PHP?


Design patterns are recurring solutions to common problems in software design.

The recommended major principles of programming

It is recommend to acknowledge the following principles before starting with


design patterns. Design patterns and OOP in general won’t make sense without
strictly following these principles.
• K.I.S.S.
• D.R.Y.
• Principle of Parsimony
• Separation of Concerns

57
• Single Responsibility Principle

Types of design patterns

According to the Gang of Four book we can categorize design patterns into three
main categories:

Creational design patterns

• Abstract Factory
• Builder
• Prototype
• Singleton

Structural design patterns

• Adapter
• Bridge
• Composite
• Decorator
• Facade
• Flyweight
• Proxy

Behavioral design patterns

• Chain of responsibility
• Command
• Intepreter
• Iterator
• Mediator
• Memento
• Observer
• State
• Strategy
• Template method
• Visitor

Other design patterns

Other design patterns that are important to know for complex applications:

58
• Dependency injection
• Lazy loading
• Mock object
• Null object
• Object pool
• Servant
• Type tunnel

See also

• DesignPatternsPHP - Sample code for several design patterns in PHP.


• Design Patterns eBook

Abstract factory design pattern in PHP

See also

• Wikipedia: Abstract factory design pattern


• DesignPatternsPHP: Abstract Factory

Adapter design pattern in PHP

See also

• Wikipedia: Adapter pattern


• DesignPatternsPHP: Adapter/Wrapper

Bridge design pattern with PHP example

See also

• Wikipedia: Bridge pattern


• DesignPatternsPHP: Bridge pattern

59
Figure 3: Adapter Design Pattern UML Diagram

Builder design pattern in PHP

See also

• Wikipedia: Builder pattern


• DesignPatternsPHP: Builder pattern

Chain of responsibility design pattern with PHP


example

See also

• Wikipedia: Chain-of-responsibility pattern


• DesignPatternsPHP: Chain Of Responsibilities

60
Command design pattern in PHP

See also

• Wikipedia: Command pattern


• DesignPatternsPHP: Command

Composite design pattern in PHP

See also

• Wikipedia: Composite pattern


• DesignPatternsPHP: Composite

Decorator design pattern with PHP example

See also

• Wikipedia: Decorator pattern


• DesignPatternsPHP: Decorator

Dependency injection design pattern in PHP


Dependency injection is a design pattern which helps to reduce tight coupling.
Let’s check the example, where we link an author to the book:
<?php

class Author
{
/**
* @var string
*/
private $firstName;

/**
* @var string
*/
private $lastName;

61
/**
* Constructor.
*
* @param string $firstName
* @param string $lastName
*/
public function __construct($firstName, $lastName)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
}
}

class Book
{
/**
* @var string
*/
private $title;

/**
* @var string
*/
private $author;

/**
* Constructor.
*
* @param string $firstName
* @param string $lastName
* @param string $title
*/
public function __construct($firstName, $lastName, $title)
{
$this->title = $title;
$this->author = new Author($firstName, $lastName);
}
}
As you can see, we have a class Author with $firstName and $lastName prop-
erties, and in the class Book constructor, we inject the properties of the Author
class along with the Book class properties and create an object of the Author
class and store it. You may think it is great code, but it is not.
Why?
• You are violating the single responsibility principle. The Book class does

62
more than representing a Book.
• You are tightly coupling the code. If you ever had to add a new property
to the Author class constructor, then you will break the Book class.
Therefore, to solve this issue, we use dependency injection, and this is how you
use it:
<?php

class Author
{
/**
* @var string
*/
private $firstName;

/**
* @var string
*/
private $lastName;

/**
* Constructor.
*
* @param string $firstName
* @param string $lastName
*/
public function __construct($firstName, $lastName)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
}
}

class Book
{
/**
* @var string
*/
private $title;

/**
* @var Author
*/
private $author;

/**

63
* Constructor.
*
* @param string $title
* @param Author $author
*/
public function __construct($title, Author $author)
{
$this->title = $title;
$this->author = $author;
}
}

$author = new Author('John', 'Doe');


$book = new Book('Some legendary book', $author);
So, as you can see, we created an object of the Author class, and passed the
variable referring to the object into the Book class. So basically, that is it about
dependency injection.

Types of Dependency Injection

Most common types of dependency injection are:


• Constructor injection
• Setter injection
• Interface injection

Constructor injection

Dependency gets injected via class constructor as shown in above example:


$author = new Author('John', 'Doe');
$book = new Book('Some legendary book', $author);

Setter injection

Dependency gets injected with class setter method:


<?php

class Author
{
/**
* @var string
*/

64
private $firstName;

/**
* @var string
*/
private $lastName;

/**
* Constructor.
*
* @param string $firstName
* @param string $lastName
*/
public function __construct($firstName, $lastName)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
}
}

class Book
{
/**
* @var string
*/
private $title;

/**
* @var Author
*/
private $author;

/**
* Set book author.
*
* @param Author $author
*/
public function setAuthor(Author $author)
{
$this->author = $author;
}

/**
* Set book title.
*
* @param string $title

65
*/
public function setTitle($title)
{
$this->title = $title;
}
}

$author = new Author('John', 'Doe');


$book = new Book();
$book->setAuthor($author);
$book->setTitle('Some legendary book');

Interface injection

Client uses interface for dependency injection.

Dependency injection container

In projects with a large number of classes utilizing the dependency injection


pattern, managing these dependencies can be solved nicely with dependency
injection container

See also

• Wikipedia: Dependency injection


• What is Dependency Injection? by Fabien Potencier
• DesignPatternsPHP: Dependency Injection
• Inversion of Control Containers and the Dependency Injection pattern
• PHP The Right Way: Dependency Injection

Facade design pattern with PHP example

See also

• Wikipedia: Facade pattern


• DesignPatternsPHP: Facade

66
Flyweight design pattern in PHP

See also

• Wikipedia: Flyweight pattern


• DesignPatternsPHP: Flyweight

Interpreter design pattern in PHP

See also

• Wikipedia: Interpreter pattern

Iterator design pattern in PHP


Iterator design pattern is a software design pattern which provides access to the
elements of an aggregate object sequentially without exposing its underlying
representation. It makes elements appear as a collection of objects.
• Promote to “full object status” the traversal of a collection.
• Polymorphic traversal

PHP implementations

• PHP offers Iterator interface out of the box. Its SPL library has also a wide
variety of useful iterators. After understanding the basics of the iterator
pattern using these instead of reinventing the wheel is more convenient.

See also

• Wikipedia: Iterator pattern


• DesignPatternsPHP: Iterator

Lazy loading design pattern in PHP


Lazy loading is a software design pattern where the initialization of an object
occurs only when it is actually needed and not before to preserve simplicity of
usage and improve performance.

67
The opposite of lazy loading is so called eager loading where the data, resource,
and object is created in the time of the initialization.

Figure 4: “Lazy Loading Design Pattern”

A practical example is reading data from the database, where each query is
expensive in terms of performance. When the data is requested via the getter
method, it is retrieved at that time and not before.
In the following example, the bar property is lazy loaded to preserve resources:
<?php

class Foo
{
/** @var mixed Reference property */
private $bar = null;

/**
* Get reference and assign it via some resource expensive method call only
* once.
*
* @return mixed
*/
public function getBar()
{
if ($this->bar == null) {
$this->bar = $this->expensiveCall();
}

return $this->bar;
}

/**
* This method makes something resource intense and calling it multiple
* times inside a single request can be avoided with above lazy loading.
*/
private function expensiveCall()
{
// ...
}

68
}

Lazy loading with closures

For lazy loading we can also use closures.


For example, let’s make the User model which represents the user entity with the
data from the database. Each user has many posts (one to many association),
so retrieving posts for each user should be lazy loaded to preserve some more
resources. Some properties and the database wrapper/ORM itself is simplified
for example purposes:
<?php

/**
* User model which calls an resource intense repository method to get posts.
*/
class User
{
/** @var array Post items */
private $posts;

/** @var Closure Reference to a user repository */


private $reference;

/**
* Set reference to a user repository method with Closure.
*
* @param Closure
*/
public function setReference(Closure $reference)
{
$this->reference = $reference;
}

/**
* Get array of items retrieved from the database with the method call of
* the repository. The retrieval from the database happens only once with
* the help of lazy loading and therefore improves performance.
*
* @return array
*/
public function getPosts()
{
if (!isset($this->posts)) {
$reference = $this->reference;

69
$this->posts = $reference();
}

return $this->posts;
}
}

/**
* Repository of users from the database.
*/
class UserRepository
{
/** @var mixed Reference to a database or ORM database manager object. */
private $database;

// ... Example is simplified for readability.

/**
* Get user and set the reference to call when requiring posts from the
* database by the given ID.
*
* @param int $id
*
* @return User
*/
public function findOneById($id)
{
$database = $this->database;
$query = $database->query('SELECT * FROM user WHERE id = :id')
$query->setParameter('id', $id);

$user = new User($query->getResult());

$reference = function($user) use($id, $database) {


$query = $database->query('SELECT * FROM post WHERE user_id = :id');
$query->setParameter('id', $id);
$userData = $query->getResult();

$posts = [];
foreach ($userData as $data) {
$posts[] = new Post($data);
}

return $posts;
};

70
$user->setReference($reference);

return $user;
}
}

PHP implementations

Some PHP examples of the lazy loading implementation include:


• Doctrine ORM Proxy
• Laravel Eloquent

See also

• Wikipedia: Lazy loading

Mediator design pattern with PHP example

See also

• Wikipedia: Mediator pattern


• DesignPatternsPHP: Mediator

Memento design pattern in PHP

UML diagram

See also

• Memento design pattern on Wikipedia


• DesignPatternsPHP: Memento

Mock object design pattern in PHP


Mock objects imitate the behavior of the real objects. They are used in testing,
where creating mock objects makes testing simpler and still provides the same
behavior as the real object used in the application code. They can also be used

71
Figure 5: Memento design pattern UML diagram

as a base while developing a specific part of an application in a team, without


utilizing the entire application.

Implementations

• PHPUnit

See also

• Wikipedia: Mock object

Null object design pattern in PHP


Null object design pattern is a software design pattern where the null object
replaces the checking for null values. It defines the default behavior of some
service class method and does nothing.

PHP example of the null object pattern

Below is a simple example of different types of commands and an application


which uses them.
<?php

interface CommandInterface
{
public function execute();

72
Figure 6: Null object design pattern UML diagram

class OutputCommand implements CommandInterface


{
public function execute()
{
echo 'Output from the command';
}
}

class FileCommand implements CommandInterface


{
public function execute()
{
file_put_contents(__DIR__.'/log.txt', date('Y-m-d H:i:s'), FILE_APPEND | LOCK_EX);
}
}

class NullCommand implements CommandInterface


{
public function execute()
{
// Do nothing.
}
}

class Application
{
public function run(CommandInterface $command = null)
{
$executableCommand = $command ?? new NullCommand();

73
return $executableCommand->execute();
}
}
Usage is then the following:
<?php
// ...

$outputCommand = new OutputCommand();


$fileCommand = new FileCommand();
$app = new Application();

// Echo predefined string


$application->run($outputCommand); // Output from the command

// Create a file and append string to it


$application->run($fileCommand);

// Do nothing
$application->run();
If we run the application without providing it the command, it does nothing,
because in that case it uses the null object NullCommand. Without the null
object, we would have to check that in the client code which becomes messy as
more commands are added or in more complex situations.

Open source PHP implementations

Some examples of the null object design pattern implementations in open source:
• NullOutput in Symfony Console
• NullHandler in Monolog

See also

• Null Object Pattern - Wikipedia article


• DesignPatternsPHP: Null Object
• The Null Object Pattern – Polymorphism in Domain Models - Sitepoint
article

74
Object pool design pattern in PHP
Object pool pattern is a software creational design pattern which is used in
situations where the cost of initializing a class instance is high. It can offer a
significant performance boost.

Figure 7: Object Pool Design Pattern UML

Object pool (resource pool) manages instantiated classes. Client code has access
to the pool and can then use it to avoid creating new objects by going through
the pool to find the one that has already been instantiated. When the pool
is empty it will create new objects. Depending on the wanted implementation
and functionality, the pool can also be set to limit the number of instantiated
classes.

PHP example of object pool

<?php

class ObjectPool
{
/** @var array Instances of reusable objects */
private $instances = [];

/**
* Get object from instances.
*
* @param string $key Key for retrieving the instance.

75
*
* @return ReusableObject
*/
public function get($key)
{
return $this->instances[$key];
}

/**
* Add object to list of instances.
*
* @param ReusableObject
*/
public function add($object, $key)
{
$this->instances[$key] = $object;
}
}

class ReusableObject
{
/**
* Do something.
*/
public function doSomething()
{
// ...
}
}

// Client code
$pool = new ObjectPool();
$reusableObject = new ReusableObject();
$pool->add($reusableObject, 'reusable_object_key')

$reusableObject = $pool->get('reusable_object_key');
$reusableObject->doSomething();

More practical examples

A practical example could also be managing a conference with call for papers.
When the call for paper is issued, speakers propose their talks and the managers
decide which speakers to invite. Speakers get assigned to talk sessions. If a
speaker cancels the talk, the talk session becomes available for the next speaker.

76
Most of the time, keep all reusable objects that are not currently in use in
the same object pool so that they can be managed by one coherent policy. To
achieve this, the reusable pool class is designed to be a singleton class.

Open source PHP implementations

• Pool in pthreads
• PSR-6 compatible cache libraries
Dependency injection container can also use object pool together with some
other design patterns.

See also

• Wikipedia: Object pool pattern


• DesignPatternsPHP: Pool

Observer design pattern in PHP

See also

• Wikipedia: Observer pattern


• DesignPatternsPHP: Observer pattern

Prototype design pattern in PHP

See also

• Wikipedia: Prototype pattern


• DesignPatternsPHP: Prototype

Proxy design pattern in PHP

See also

• Wikipedia: Proxy pattern


• DesignPatternsPHP: Proxy

77
Figure 8: Proxy design pattern UML diagram

Servant design pattern in PHP


Servant design pattern is a behavioral design pattern where multiple classes use
the servant’s class behavior to avoid repeating code (see: DRY). Behavior
functionality is defined only in one place: In servant.
The servant design pattern is not a defined pattern in the Gang of Four (GoF)
book. It is very similar to the command design pattern but with a somewhat
different solution to the problem.

Figure 9: Servant design pattern UML

78
See also

• Wikipedia: Servant design pattern

Singleton design pattern in PHP


The Singleton design pattern is a creational design pattern where a class ensures
it has only one instance with lazy initialization, and can be accessed from a
global scope. It has encapsulated “just-in-time initialization” or “initialization
on first use”.
To solve this, we could use global variables (constants) inside a class. However,
this doesn’t make classes modular and can be used only for the current appli-
cation implementation. Therefore, this is considered a bad practice. Another
approach to solve this would be to use the singleton pattern.

Figure 10: Singleton design pattern uml Diagram

PHP example of a Singleton class:


<?php

class Singleton
{
/** @var Singleton Reference to singleton class instance. */
private static $instance;

/**
* Private constructor ensures the class can be initialized only from
* itself.
*/
private function __construct() {}

79
/**
* Get a singleton class instance with lazy initialization only on first
* call. Client code can therefore use only this accessor method to
* manipulate the singleton.
*
* @return Singleton
*/
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new self();
}

return self::$instance;
}

/**
* @throws Exception to prevent cloning object.
*/
public function __clone()
{
throw new Exception('You cannot clone singleton object');
}
}
The singleton pattern can be extended to support access to an application-
specific number of instances.
Inheritance of the singleton class is not possible when using a static accessor
method. Also, deleting an instance of a singleton class is a non-trivial design
problem.

When to use the singleton pattern?

A singleton should be considered only if all of the following criteria are met:
• Ownership of the single instance cannot be reasonably assigned.
• Lazy initialization is desirable.
• Global access is not otherwise provided (in case of legacy applications).
If the above criteria does not present implementation issues in the application
code, then in most cases, the dependency injection should be used for better
testability and flexible maintainability.
When accessing the global scope, the advantage of the singleton pattern over
global variables is that it ensures the number of instances which can be changed
to any required number any time.

80
The same as using global variables inside classes, the singleton pattern imple-
mented on class level is considered an anti-pattern because it reduces testability
and maintainability of the code. To replace global variables with a singleton is
a wrong approach to solve access of global scope from a class.
A singleton can be used when it is simpler to pass an object resource as a
reference to the objects that need it instead of letting objects access the resource
globally. It might be useful and handy to use a singleton, but the appropriate
visibility of an object must be thought through.
The singleton pattern implemented on factory, incubator, or service container
level is not an anti-pattern. Abstract factory, builder, and prototype can use
a singleton in their implementation. Facade and state objects are also often a
singleton, because only one class instance is required.

See also

• Wikipedia: Singleton pattern


• DesignPatternsPHP: Singleton

State design pattern in PHP

See also

• Wikipedia: State pattern


• DesignPatternsPHP: State

Strategy design pattern in PHP

See also

• Wikipedia: Strategy pattern


• DesignPatternsPHP: Strategy

Template method design pattern in PHP

See also

• Wikipedia: Template method pattern


• DesignPatternsPHP: Template method

81
Type tunnel design pattern in PHP
The type tunnel pattern is not exactly a recognized software design pattern by
GoF (Gang of Four book). Type tunnel is used in cases where multiple unrelated
types are passed (tunneled) through adaptation layer and converted to the type
the underlying layer expects.

Figure 11: Type tunnel design pattern UML

Type tunnel also has side effects that compensate its benefits, because in a
dynamically typed language such as PHP, the types can be solved differently.
It can be used best in statically typed programming languages such as C++,
but in case of PHP, implementing type tunnel isn’t really applicable.

See also

• Type Tunnel
• Generalized String Manipulation: Access Shims and Type Tunneling
• PHP Types

Visitor design pattern in PHP

See also

• Wikipedia: Visitor pattern


• DesignPatternsPHP: Visitor pattern

82
What is an anti-pattern?
An anti-pattern is a common response to a recurring problem that
is usually ineffective and risks being highly counterproductive. The
term, coined in 1995 by Andrew Koenig, was inspired by a book,
“Design Patterns”, which highlights a number of design patterns in
software development that its authors considered to be highly reli-
able and effective.
• Wikipedia

See also

• AntiPatterns eBook

What is a database and how to access databases


from PHP?
A database is an organized collection of data. The data is typically organized to
model aspects of reality in a way that supports processes requiring information.
For example, modelling the availability of rooms in hotels in a way that supports
finding a hotel with vacancies.
A database management system (DBMS) is an application that interacts with
the database, captures and analyzes the data.

Application examples

Databases are used to support internal operations of organizations and to un-


derpin online interactions with customers and suppliers.
Areas and examples where DBMS are used:
• Content Management System (CMS)
• E-commerce store with products, catalogs and customers
• Banking: For customer information, accounts, and loans, and banking
transactions.
• Airlines: For reservations and schedule information. Airlines were among
the first to use databases in a geographically distributed manner - ter-
minals situated around the world accessed the central database system
through phone lines and other data networks.
• Universities: For student information, course registrations, and grades.

83
• Credit card transactions: For purchases on credit cards and generation of
monthly statements.
• Telecommunication: For keeping records of calls made, generating monthly
bills, maintaining balances on prepaid calling cards, and storing informa-
tion about the communication networks.
• Finance: For storing information about holdings, sales, and purchases of
financial instruments such as stocks and bonds.
• Sales: For customer, product, and purchase information.
• Manufacturing: Management of supply chain, tracking factory production,
inventories of items in warehouses, and orders for items.
• Human resources: Information about employees, salaries, payroll taxes
and benefits, and paychecks generation.

Database access from PHP

PHP has in its core multiple extensions for accessing different types of databases.
Before accessing database from PHP learn SQL (Structured Query Language).
SQL is a language designed to manage data stored in relational databases.
After getting a grip with basics many applications abstract the database layer,
customize SQL for more advanced, efficient and better ways to access databases.
For more information about this check PHP ORMs.

See also

Other resources you should check out:


• Codecademy: Learn SQL
• PDO tutorial for MySQL developers
• PHP.net: Database Security
• Related FAQ: What is SQL injection and how to prevent it?
• Related FAQ: What is PDO?
• Related FAQ: Why are mysql_* functions removed and what to do?
• Wikipedia

Why are mysql_* functions removed and what


to do?
If your code has mysql_connect(), mysql_query() and other mysql_* func-
tions, they will not work anymore in the latest version of PHP 7.
MySQL extension (ext/mysql) with all mysql_* functions has been deprecated
in PHP 5.5 and removed in PHP 7.

84
How to fix it?

In PHP there are multiple ways to access database (PDO, ORMs, or mysqli for
MySQL and MariaDB databases). Fixing legacy and old code is recommended
and shouldn’t be very difficult and time consuming task by refactoring it to
PDO_MySQL extension or mysqli.
Here is an example of writing code in the old way by using mysql_* functions:
$link = mysql_connect('localhost', 'db_user', 'db_password');
if (!$link) {
die('Connection failed: ' . mysql_error());
}
$database = mysql_select_db('db_name', $link);

$firstName = filter_has_var(INPUT_GET, 'firstName') ? filter_input(INPUT_GET, 'firstName', F

$query = sprintf("SELECT username FROM friends


WHERE first_name='%s'",
mysql_real_escape_string($firstName));

$result = mysql_query($query);

while ($row = mysql_fetch_assoc($result) {


echo $row['username'];
}
Let’s refactor above into PDO - the modern and future proof way to access
database. PDO’s prepared statements below take care also of SQL injections:
$pdo = new PDO('mysql:host=localhost;dbname=db_name', 'db_user', 'db_password');

$firstName = filter_has_var(INPUT_GET, 'firstName') ? filter_input(INPUT_GET, 'firstName', F

$params = [':firstName' => $firstName];

$sth = $pdo->prepare('
SELECT username FROM friends
WHERE first_name = :firstName');
$sth->bindParam(':firstName', $firstName, PDO::PARAM_STR);
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_ASSOC);
foreach ($result as $row) {
echo $row['username'];
}

85
MySQL improved extension - MySQLi

In case of MySQL database there is also MySQLi extension available which


works perfectly fine and is simple enough to use and migrate your mysql_*
based code to work on PHP 7. But you will be limited to only one database
(if you change your mind later and want to move to some other database for
instance PostgreSQL) and also be deprived of some other functionalities in PDO.
So, recommended way is to just use PDO.
For migration to mysqli you could use MySQL Converter tool but to be sure
better go through the code manually. MySQLi offers two APIs - OOP and
procedural.
Let’s refactor above code into mysqli procedural way and prepared statements
(for avoiding SQL injection):
$link = mysqli_connect('localhost', 'db_user', 'db_password', 'db_name');

if (mysqli_connect_errno()) {
die('Connect failed: ' . mysqli_connect_error());
}

$firstName = filter_has_var(INPUT_GET, 'firstName') ? filter_input(INPUT_GET, 'firstName', F

$query = "SELECT username FROM friends WHERE first_name=?";

if ($stmt = mysqli_prepare($link, $query)) {


mysqli_stmt_bind_param($stmt, 's', $firstName);
mysqli_stmt_execute($stmt);

// bind result variables


mysqli_stmt_bind_result($stmt, $username);

// fetch values
while (mysqli_stmt_fetch($stmt)) {
echo $username;
}

// close statement
mysqli_stmt_close($stmt);
}
Let’s refactor above code into mysqli object oriented way:
$mysqli = new mysqli('localhost', 'db_user', 'db_password', 'db_name');

if ($mysqli->connect_error) {
die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);

86
}

$firstName = filter_has_var(INPUT_GET, 'firstName') ? filter_input(INPUT_GET, 'firstName', F

$stmt = $mysqli->prepare("SELECT username FROM friends WHERE first_name=?");


$stmt->bind_param('s', $firstName);
$stmt->execute();
$stmt->bind_result($username);
while ($stmt->fetch()) {
echo $username;
}
$stmt->close();

Why is MySQL extension deprecated?

MySQL extension has been in PHP core from the very early 2.0 version - it
was over 15 years old. One of the main reasons for removal was difficult
and complicated maintenance in the PHP core. MySQL extension also doesn’t
provide all the latest features and benefits of the MySQL database.

See also

• PDO tutorial
• PDO Tutorial for MySQL Developers
• Related FAQ: What is ORM? - Advanced ways to access databases in
PHP.
• Supercharging PHP MySQL applications using the best API - Blog post
explaining why upgrading from ext/mysql is a good idea.

PDO vs. mysqli?


For connecting to MySQL or MariaDB database PHP offers two APIs: PDO
with PDO_MySQL driver and mysqli. Before PHP 7 there was also ext/mysql
which is not recommended for usage anymore.
Feature differences between mysqli and PDO:

Feature PDO MySQLi


Database support 12 different drivers MySQL and Maria
Interface OOP OOP and procedu
Named parameters Yes No
Object mapping Yes Yes

87
Feature PDO MySQLi
Prepared statements Yes Yes
Non-blocking, asynchronous queries with mysqlnd support No Yes
Multiple Statements support Most Yes
MySQL 5.1+ functionality support Most All

Database connection

// PDO
$pdo = new PDO("mysql:host=localhost;dbname=database;charset=utf8", 'username', 'password');

// mysqli, procedural way


$mysqli = mysqli_connect('localhost', 'username', 'password', 'database');

// mysqli, object oriented way


$mysqli = new mysqli('localhost', 'username', 'password', 'database');

Databases support

The core advantage of PDO over MySQLi is in its database driver support. At
the time of this writing, PDO supports 12 different drivers, opposed to MySQLi,
which supports only MySQL and MariaDB databases.

Named parameters

Another important feature of PDO is easier parameters binding instead of nu-


meric binding:
$params = [':username' => 'test', ':email' => $mail, ':last_login' => time() - 3600];

$pdo->prepare('
SELECT * FROM users
WHERE username = :username
AND email = :email
AND last_login > :last_login');

$pdo->execute($params);
MySQLi provides question mark parameter binding and doesn’t support named
parameters:
$query = $mysqli->prepare('
SELECT * FROM users

88
WHERE username = ?
AND email = ?
AND last_login > ?');

$query->bind_param('sss', 'test', $mail, time() - 3600);


$query->execute();
The question mark parameter binding might seem shorter, but it isn’t nearly as
flexible as named parameters, due to the fact that the developer must always
keep track of the parameter order; it feels “hacky” in some circumstances.

Object mapping

Both PDO and MySQLi can map results to objects. This comes in handy if you
don’t want to use a custom database abstraction layer, but still want ORM-like
behavior. Let’s imagine that we have a User class with some properties, which
match field names from a database.
class User
{
public $id;
public $first_name;
public $last_name;

public function info()


{
return '#'.$this->id.': '.$this->first_name.' '.$this->last_name;
}
}
Without object mapping, we would need to fill each field’s value (either manually
or through the constructor) before we can use the info() method correctly.
This allows us to predefine these properties before the object is even constructed.
For instance:
$query = "SELECT id, first_name, last_name FROM users";

// PDO
$result = $pdo->query($query);
$result->setFetchMode(PDO::FETCH_CLASS, 'User');

while ($user = $result->fetch()) {


echo $user->info()."\n";
}

// MySQLI, procedural way

89
if ($result = mysqli_query($mysqli, $query)) {
while ($user = mysqli_fetch_object($result, 'User')) {
echo $user->info()."\n";
}
}

// MySQLi, object oriented way


if ($result = $mysqli->query($query)) {
while ($user = $result->fetch_object('User')) {
echo $user->info()."\n";
}
}

Security

Let’s say a hacker is trying to inject some malicious SQL through the username
HTTP query parameter (GET):
$_GET['username'] = "'; DELETE FROM users; /*"
If we fail to escape this, it will be included in the query “as is” - deleting all
rows from the users table (both PDO and mysqli support multiple queries).
// PDO, "manual" escaping
$username = PDO::quote($_GET['username']);

$pdo->query("SELECT * FROM users WHERE username = $username");

// mysqli, "manual" escaping


$username = mysqli_real_escape_string($_GET['username']);

$mysqli->query("SELECT * FROM users WHERE username = '$username'");


As you can see, PDO::quote() not only escapes the string, but it also quotes it.
On the other side, mysqli_real_escape_string() will only escape the string.
You will need to apply the quotes manually.
// PDO, prepared statement
$pdo->prepare('SELECT * FROM users WHERE username = :username');
$pdo->execute([':username' => $_GET['username']);

// mysqli, prepared statements


$query = $mysqli->prepare('SELECT * FROM users WHERE username = ?');
$query->bind_param('s', $_GET['username']);
$query->execute();
Recommendation is to always use prepared statements with bound queries in-
stead of PDO::quote() and mysqli_real_escape_string().

90
Performance

While both PDO and MySQLi are quite fast, MySQLi performs insignificantly
faster in benchmarks - ~2.5% for non-prepared statements, and ~6.5% for pre-
pared ones. The MySQL extension was even faster.

See also

• PHP manual - Choosing an API for accessing MySQL or MariaDB


databases.

What is PDO?
PDO stands for “PHP Data Object”, which is one of the many ways available
for accessing databases in PHP. You can think of it as an alternative to using
MySQLi or mysql_ functions (deprecated). However, it’s not specific to MySQL
databases, it can be used with many different types of databases. So with PDO
you can access your database very easily.

Why PDO over others?

You might think, why would I prefer to use it over others? Well, there are many
reasons, but the main one is because it uses the same API regardless of which
database driver you’re using. For example, if you were using SQLite database,
you can switch to MySQL very easily; you have to change only the type of the
driver PDO uses (which you specify in the DSN string), the rest are dependent
on compatibility of SQL/features you used.
PDO currently supports 12 different databases:
• Cubrid
• FreeTDS / Microsoft SQL Server / Sybase
• Firebird
• IBM DB2
• IBM Informix Dynamic Server
• MySQL 3.x/4.x/5.x
• Oracle Call Interface
• ODBC v3 (IBM DB2, unixODBC and win32 ODBC)
• PostgreSQL
• SQLite 3 and SQLite 2
• Microsoft SQL Server / SQL Azure
• 4D

91
PDO also supports named parameters in prepared statements over other exten-
sions.

Connection

Connection to a database is established simply by instantiating the PDO object


with required data for the connection. It looks like this:
$pdo = new PDO('mysql:host=localhost;dbname=your_database_name', $username, $password);
Don’t worry if this seems confusing to you; In the first parameter we specify the
DSN (Data Source Name), which is a simple string that specifies the type of
driver we’re connecting to (in this case mysql), then followed by a colon which
followed by some options required for the connection, in this case: the host and
the database name. Then in the last two parameters we put the username and
the password for our database.
Now what if the connection fails? In this case the PDO object will throw an
exception of PDOException type, which includes the errors that occurred during
connection. So we need to catch that exception and display those errors:
<?php

try {
$pdo = new PDO('mysql:host=localhost;dbname=your_database_name', $username, $password);
} catch (PDOException $e) {
echo $e->getMessage();
}

Allow exceptions

What would happened if an error occurred while dealing with the database? For
example table we’re retrieving data from doesn’t exist. With default settings,
we would have to use $pdo->errorCode() and $pdo->errorInfo() to fetch the
errors. A better way is to convert all the errors to exceptions:
<?php

try {
$pdo = new PDO('mysql:host=localhost;dbname=your_database_name', $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo $e->getMessage();
}
So we can specify our configurations by using the $pdo->setAttribute()
method. The default value for PDO::ATTR_ERRMODE is PDO::ERRMODE_SILENT.

92
Another option is to convert errors to PHP warnings using PDO::ERRMODE_WARNING.
Having said that, it’s better to stick with exceptions.

Retrieving data

To retrieve data with PDO, use the PDO::query() method. It takes the query
string you want to execute (the normal SQL query) and returns PDOStatement
object. PDOStatement object has various methods for dealing with results.
To retrieve data from PDOStatement you can use PDOStatement::fetch()
or PDOStatement::fetchAll(). PDOStatement::fetch() returns single row
while PDOStatement::fetchAll() returns all rows. Both methods return data
as array by default.
<?php

try {
$pdo = new PDO('mysql:host=localhost;dbname=your_database_name', $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $pdo->query('SELECT * from users');


$data = $stmt->fetchAll();
foreach ($data as $row) {
var_dump($row);
}
} catch (PDOException $e) {
echo $e->getMessage();
}
PDOStatement objects also implemented Traversable interface, so you can it-
erate through them using foreach.
<?php

try {
$pdo = new PDO('mysql:host=localhost;dbname=your_database_name', $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $pdo->query('SELECT * from users');


foreach ($stmt as $row) {
var_dump($row);
}
} catch (PDOException $e) {
echo $e->getMessage();
}
But note that PDOStatement objects are not Iterator.

93
As you may know, when executing a query that requires external data from the
user (like id), we should escape it before executing it. For this we can use the
$pdo->quote() method:
<?php

try {
$pdo = new PDO('mysql:host=localhost;dbname=your_database_name', $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$data = $pdo->query('SELECT * from users WHERE id = ' . $pdo->quote($id));


} catch (PDOException $e) {
echo $e->getMessage();
}
Even though this works, next you’ll see a better way to do it ‐ prepared state-
ments.

Prepared statements

Using PDO::query() is great when the user’s data is hardcoded (no external
data). However, most of our queries use data from outside ($_GET or $_POST).
In these cases we have to be careful of SQL injections. Although we can escape
those data manually, PDO provides a better way by using prepared statements.
Think of prepared statements as a way to prepare your query before executing
it. There are lots of benefits we can get from this. First we have the ability to
execute the same statements multiple time with different data. Also it provides
a safer way to use user’s data in our queries (by binding values).
Here’s an example of how to retrieve data with it:
<?php

try {
$pdo = new PDO('mysql:host=localhost;dbname=your_database_name', $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$statement = $pdo->prepare('SELECT * FROM users WHERE id = :id'); // prepare the stateme


$statement->execute([':id' => $id]); // execute it
$result = $statement->fetch(); // fetch the result
var_dump($result); // show the result

// use the same statement with different id


$statement->execute([':id' => $anotherId]); // execute it
$result = $statement->fetch(); // fetch the result
var_dump($result); // show the result

94
} catch (PDOException $e) {
echo $e->getMessage();
}
The PDO::prepare() method takes a normal SQL statement and replaces the
user’s data with a placeholder (in this case :id). Then we execute the statement
using the PDOStatement::execute() method, which takes an array that con-
tains the data that should be bound to the placeholders. With this approach,
we make sure that SQL injection is impossible.
We get a PDOStatement object when executing PDO::prepare(). We use this
object to retrieve data related to our executed statement. For example, we
use PDOStatement::fetchAll() or PDOStatement::fetch() to fetch the data
from database. To get the number of rows affected by the last SQL statement
we can use PDOStatement::rowCount().
Notice we represent the placeholder by a colon followed by any name we want.
This is what we call a named parameter. Alternatively, we can represent the
placeholder with a question mark (?), which then we have to bind them accord-
ing to their positions. As a rule of thumb, always use the named parameter
because it’s easier and more readable.
In case you’re wondering what’s the difference between PDOStatement::fetch()
and PDOStatement::fetchAll(), where former is used to fetch only the first
row that matches the query, and the latter is used to fetch all rows and return
them as an array. With PDOStatement::fetch() we can only access the
results by looping over them row by row. PDOStatement::fetchAll() on the
other hand, returns an array which we can deal with it as we want. This is
useful for operations that depend on the overall result.

Specify how to fetch

When we fetch data using PDOStatement::fetch() or PDOStatement::fetchAll(),


we get the result as an array that is indexed by both column-name and numerical
indexed:
array (size=6)
'id' => string '1' (length=1)
0 => string '1' (length=1)
'name' => string 'foo' (length=8)
1 => string 'foo' (length=8)
'email' => string 'foo@example.com' (length=15)
2 => string 'foo@example.com' (length=15)
While this is the default way of fetching, we can change it easily by passing a
value to the fetch method. This value can be one of the following:
• PDO::FETCH_BOTH (the default)

95
• PDO::FETCH_ASSOC
• PDO::FETCH_BOUND
• PDO::FETCH_CLASS
• PDO::FETCH_OBJ
We’re most concerned with the second and last one. We use PDO::FETCH_ASSOC
to fetch the result in form of an array with string (column names) keys. And
PDO::FETCH_OBJ returns an object of class stdClass with column names as
property names.
Here’s an example of PDO::FETCH_ASSOC:
<?php

$statement = $pdo->prepare('SELECT * FROM users WHERE id = :id');


$statement->execute([':id' => $id]);
$result = $statement->fetch(PDO::FETCH_ASSOC); // result is in an associative array
var_dump($result['email']); // to display the email of user with id = $id
Example of PDO::FETCH_OBJ:
<?php

$statement = $pdo->prepare('SELECT * FROM users WHERE id = :id');


$statement->execute([':id' => $id]);
$result = $statement->fetch(PDO::FETCH_OBJ); // result is in an object
var_dump($result->email); // to display the email of user with id = $id
For consistency, you can specify the option you want as a default for later queries.
To do so, set an attribute of PDO::ATTR_DEFAULT_FETCH_MODE to
what you want:
<?php

try {
$pdo = new PDO('mysql:host=localhost;dbname=your_database_name', $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

} catch (PDOException $e) {


echo $e->getMessage();
}

CRUD examples

Above examples were only for reading data from database. Let’s review other
CRUD (Create, Read, Update and Delete) operations.

96
Insert

<?php

$statement = $pdo->prepare('INSERT Into users(name, email) VALUES(:name, :email)');


$statement->execute([
':name' => $name,
':email' => $email
]);

var_dump($result->rowCount()); //number of affected rows: 1

Update

<?php

$statement = $pdo->prepare('UPDATE users SET name = :name WHERE id = :id');


$statement->execute([
':id' => $id,
':name' => $name
]);
var_dump($result->rowCount()); //number of affected rows: 1

Delete

<?php

$statement = $pdo->prepare('DELETE FROM users WHERE id = :id');


$statement->execute([':id' => $id]);

var_dump($result->rowCount()); //number of affected rows: 1

See also

• PDO tutorial
• PDO Tutorial for MySQL Developers

Database management systems vs. file systems?

Database management systems vs. file systems

• DBMS - A computerized record-keeping system

97
• File System - A collection of individual files accessed by applications pro-
grams.

Common limitations of some file system based DBs

• Separated and Isolated Data - Makes coordinating, assimilating and rep-


resenting data difficult
• Data Duplication - Wastes space and can lead to data integrity (inconsis-
tency) problems
• Application Program Dependencies - Changes to a single file can require
changes to numerous application programs
• Incompatible Files

Advantages of a DBMS

• Data Consistency and Integrity - by controlling access and minimizing


data duplication
• Application program independence - by storing data in a uniform fashion
• Data Sharing - by controlling access to data items, many users can access
data concurrently
• Checkpointing and Recovery
• Security and Privacy
• Multiple views of data
• Expandability, Flexibility, Scalability
• Reduced application development times once the system is in place
• Standards enforcement
• However …..
• Commercial DBMS often have high initial cost
• Many DBMSs have high overhead - require powerful computers
• DBMS are not special purpose software programs
• Performance depends on the application

When is a DBMS not necessarily appropriate?

• Database is small with a simple structure


• Applications are simple, special purpose and relatively static.

98
• Concurrent, multi-user access to data is not required.
• Need a quick prototype to demonstrate feasibility
• Need an easy way to see the data without having to write a program
• Customers don’t want to install a DBMS and want to get online quickly

MongoDB vs. MySQL


Most common used and suggested database is most likely MySQL.
MySQL is a relational database management system (RDBMS) which has been
around for decades. As a database system, RDBMS stores data in a database
object called table. Table is a structure of dataset consist of row and column.
In order to access the data stored in RDBMS, SQL language is used. The SQL
use statement: SELECT, INSERT, UPDATE, DELETE to manipulate the data
stored in database system.
RDBMS and its SQL language has been an industrial standard database sys-
tem, since 1986 ANSI (American National Standard of Industry) issued an SQL
standard. Then in 1987, International Standard of Organization (ISO) issued
SQL standard as International standard as ISO/IEC 9075. However, in many
RDBMS, there are variations of SQL from the ISO and ANSI standard, which
unique to each database. However, the basic standard is the same in every
database using SQL.

MySQL

MySQL is the popular database which has been around since 1995. The
database was released under the GNU GPL License, which made the source
code available. MySQL was issued by MySQL AB, a Swedish company.
MySQL gains popularity as the top database for web application due to the
LAMP and others software stack with AMP acronym. LAMP is an acronym
for Linux-Apache-MySQL-PHP, a software stack which implemented in large
numbers of web application.
Due to the popularity of MySQL, Sun Microsystem, a company that sells com-
puters and the inventor of Java Programming language, acquired MySQL AB
as one of their subsidiary in 2008. Sun made the move in order to strengthen its
position in the Open Source software landscape. Previously, they had acquired
StarOffice in 1999, a German company that produces office suite that became
OpenOffice.
In 2010, Oracle the database giant bought Sun Microsystem and therefore be-
come the owner of MySQL. This made Oracle has the cutting edge in the
database industry. With the ownership of MySQL through the acquisition of
Sun Microsystem, Oracle has two database product offered to their customers,

99
Oracle database for a big corporate customers and MySQL for private use. What
is the different between Oracle Database and MySQL? There are some differ-
ences in terms of their system management and details.
However, there is one downside of SQL to deal with the real life data. In the
business world, most data we have today is a non-structured data, meaning as
the data that cannot be stored in a traditional SQL tabular model, known as
structured data. Structured data is data which have a predefined data model
that can be stored in SQL row and column format. Unstructured data refers to
text-extensive data which may have numbers and structured data in the text,
but it cannot be stored in the traditional SQL database. This unstructured data
is the most of data we deal in daily life. Merril Lynch in 1998 made estimation
that 80% to 90% of business data is originated from unstructured form.
Therefore, most of the data in our life cannot be stored in SQL format.

NoSQL and MongoDB

Meanwhile, the reliance of unstructured data in every aspect of life is increasing


rapidly. With the huge amounts of data in the web, the need to have a database
to store documents in becomes imperative. The initiative of creating a database
capable of storing unstructured data began with NoSQL.
The idea of NoSQL started in 1998. The name is a database created by Carlo
Strozzi, who made its database management system and use a stream-operator
paradigm to access data instead of SQL syntax, Stream operator paradigm is a
database operator which resemble a mathematical operation in order to access
data stored in database. Nevertheless, NoSQL is still using RDBMS model,
therefore it has SQL equivalent in NoSQL operator and it does not really support
the need to store document in database. NoSQL RDBMS is only qualified as
“NoSQL RDBMS.”
The quest for new database without SQL to store document and unstructured
data has made the term NoSQL became generic terms for that purpose.
MongoDB came with the aim of providing the new way of data storage. There-
fore database can store document for the world wide web. Began in 2007, Mon-
goDB is built to store data as an object in a dynamic schema, instead of a
tabular database like SQL. The data in MongoDB is stored as object notation
based on the format of JSON (Java Script Object Notation). JSON is a stan-
dard for data transfer over the network between the server and web application
using human readable format. Prior to JSON, the XML is used for that purpose.
MongoDB modified the JSON format into its own BSON, which store the ob-
ject in a binary format instead of human readable format. Hence the acronym
BSON stands for Binary JSON. BSON, due to its binary format provide more
reliable and more efficient in storage space and speed.

100
The popularity of MongoDB gains when users love to use MongoDB for it de-
livers its promise as a document-oriented database. The prominent MongoDB
user are Craigslist that has 2 billion of its records stored in MongoDB; Forbes
and New York Times that use it to store their articles and photos; Shutterfly for
its photo database that contained about 18 billion of photos; and Foursquare.
The emergence of web-oriented data has shifted the database landscape with the
arrival of Big Data. As Gartner, a prominent information technology research
and advisory firm has coined the term Big Data in 2001. Big Data is the
data which due to its nature can not be stored in a tabular model of relational
database management system as exist today with the SQL syntax to manipulate
the data.
Big data has grown and the 3-V that Gartner mentioned regarding the data
growth challenges and opportunities were three-dimensional, which are increas-
ing volume (the amount of data), velocity (the speed of data transfer), and
variety (the range of data types and sources) has come to our everyday life. We
are now dealing with that kind of data daily.
Just imagine, we are now dealing with terabyte of data every day in data transfer,
things we hardly found in 5-10 years ago. We also deal with the rapid increasing
speed of data transfer through the advancement of computing technology which
happens real fast. We also deal with the various source of data. The data we
are analyzing is from multiple source in a multiple forms. We have a streaming
video, image and audio video beside text. We practically can tap data anywhere
we want it and anytime we want to in a various format, with multiple size and
multiple source.
This kind of unstructured data with its massive size in a single file hence the
name Big Data is given to them, require a different approach to handle. We need
more than just traditional SQL which is extremely good to manage structured
data in its tabular format of row and column. However the unstructured data
which take up to 90% of data we manage requires a non-tabular storage. We
simply cannot rely on the SQL and traditional relational database management
system to store and manage the data in form of multimedia file, image, blog
and articles. We need a document oriented data which is MongoDB came from
instead of MySQL to manage different kind of data: unstructured rather than
structured data.

Conclusion

Attempting a comparison between MySQL vs MongoDB is actually an apples


to oranges type of challenge. We simply cannot devise a winner. MySQL is a
RDBMS with SQL that has a rigid data model which required data to be stored
in tabular model: the rows and columns. It is useful to organize your structured
data like sales statistics. On the other hand, MongoDB is a document oriented

101
database, which store document and treat the document as data. It has very
different approach than MySQL. Choose the one that works best for you!

What is ORM?
ORM (Object-relational mapping), also known as O/RM, and O/R mapping is a
programming approach for converting data between incompatible type systems.
Many full stack frameworks provide their own database abstraction approaches
or ORMs.
Standalone database abstraction layers and ORMs to check out:
• Aura SQL - Extension to the native PDO along with a profiler and con-
nection locator.
• DataMonkey - Database ORM for PHP build on top of Doctrine.
• Doctrine - Home to several PHP libraries primarily focused on database
storage and object mapping. The core projects are a Object Relational
Mapper (ORM) and the Database Abstraction Layer (DBAL) it is built
upon.
• Eloquent - Illuminate Database component, used in Laravel framework
but also a standalone component.
• Medoo - Light PHP database framework to accelerate development.
• Propel - A highly customizable and blazing fast ORM library.
• ProxyManager - Library that aims at providing abstraction for generating
various kinds of proxy classes.
• RedBeanPHP - Easy to use ORM for PHP.
• safemysql - A real safe and convenient way to handle MySQL queries.
• Spot ORM - simple and efficient DataMapper built on Doctrine Database
Abstraction Layer.
• Zend\Db - Zend Database Component.

Design patterns

There are mainly two main design patterns used in ORMs - Active Record and
Data Mapper.

When not to use ORM?

As some articles have pointed out (1, 2, 3), ORM is anti-pattern that violates
principles of object-oriented programming.
As an alternative to ORM, there is Pomm. It does not propose an abstrac-
tion layer and is dedicated to Postgres making developpers able to code directly

102
in SQL to fetch entities. It matches object/relational impedance by using the
projection relational operation in order to hydrate flexible instances. It is par-
ticulariry suited to build in-house transactional or reporting applications.

See also

Here are some other useful and updated resources to read or check as well:
• ActiveRecord and the Beauty Lost in Translation
• Lessql - Lightweight and efficient alternative to ORM for PHP.

How to store files in a database?


This is a common question that will normally be answered with a prejudiced
answer. Technically, databases are able to hold binary data without bigger
performance issues, and it is a fact that storing binary data to a database is
common practice (e.g., for IP addresses).
The common answer that “storing files into databases is the worst thing you
could do” is simply wrong because it depends on what you will store and how
it will scale.
The general problem of storing files outside of databases and “reference to stor-
age places with file paths” is that isn’t any file system mechanism which could
take action to automatically sync the database with the file system state. So, if
you delete a file from the database, you have to delete it by yourself from the
storage-space of your file system and vice versa.
The biggest issue about files that are referenced in a database appears when you
backup a database by making a snapshot. It will be close to impossible to store
a backup of the “current state” of files stored outside the database, because it
will be possible to touch such files while the snapshot is being created. Integrity
in backups matters, which is difficult when referenced parts decentralize.
The general problem of storing files inside of databases as part of a table or as
a table referenced to other tables is the maximum storage size of the database
engine and some limits of the file system and streams used by the database. If
you wouldn’t ever touch those limits, you’ll be fine with storing your files in the
database. On contrary to the file system, binary data stored at the database will
also allocate a bit more memory at the storage because of indexes and metadata
for those rows. Nothing to struggle with, but it should be included with the
blueprints of the database(-cluster) that are set in stone.
The biggest issue about files in databases is that a native connection to a
database in a PHP environment takes more than a second. A file stream to
the client, however, will keep the database connection open until the database

103
sends the last bit of the stored binary data. This can be an issue because of the
max_connection limit of the database. It should be considered when building
the database platform if the database is intended to be used for file storage.
Caching frequently requested files can be a good solution.
So, using the database as a file storage is possible and performant. It is an
option to consider and depends on your infrastructure. A database that holds all
(binary) data that’s referenced inside the database is a totally synced database.
If this is a must for your project and backup plans, you have to depend on it.
Databases are good for one thing: holding data. They do not care, regardless
of whether it’s 1 byte or 10 gigabytes.

How to secure PHP web applications and prevent


attacks?
As a developer you must know how to build a secure and bulletproof application.
Your duty is to prevent security attacks and secure your application.

Checklist of PHP and web security issues

Make sure you have these items sorted out when deploying your application into
production environment:
1. � Cross site scripting (XSS)
2. � Injections
• � SQL injection
• � Directory traversal (path injection)
• � Command injection
• � Code injection
3. � Cross site request forgery (XSRF/CSRF)
4. � Public files
5. � Passwords
6. � Uploading files
7. � Session hijacking
8. � Remote file inclusion
9. � PHP configuration
• � Error reporting
• � Exposing PHP Version
• � Remote files
• � open_basedir
• � Session settings
10. � Use HTTPS
11. � Things not listed

104
Cross site scripting (XSS)

XSS attack happens where client side code (usually JavaScript) gets injected
into the output of your PHP script. This can be through the URL, but can also
be done via a stored technique such as the database.
// GET data is sent through URL: http://example.com/search.php?search=<script>alert('test')<
$search = $_GET['search'] ?? null;
echo 'Search results for '.$search;

// This can be solved with htmlspecialchars


$search = htmlspecialchars($search, ENT_QUOTES, 'UTF-8');
echo 'Search results for '.$search;
• ENT_QUOTES is used to escape single and double quotes beside HTML
entities
• UTF-8 is used for pre PHP 5.4 environments (now it is default). In some
browsers some characters might get pass the htmlspecialchars().

Injections

SQL injection

When accessing databases from your application, SQL injection attack can hap-
pen by injecting malicious SQL parts into your existing SQL statement.
• More details available in “What is SQL injection and how to prevent it?”
FAQ.

Directory traversal (path injection)

Directory traversal attack is also known as ../ (dot, dot, slash) attack. It
happens where user supplies input file names and can traverse to parent direc-
tory. Data can be set as index.php?page=../secret or /var/www/secret or
something more catastrophic:
$page = $_GET['page'] ?? 'home';

require $page;
// or something like this
echo file_get_contents('../pages/'.$page.'.php');
In such cases you must check if there are attempts to access parent or some
remote folder:
// Checking if the string contains parent directory
if (strstr($_GET['page'], '../') !== false) {

105
throw new \Exception("Directory traversal attempt!");
}

// Checking remote file inclusions


if (strstr($_GET['page'], 'file://') !== false) {
throw new \Exception("Remote file inclusion attempt!");
}

// Using whitelists of pages that are allowed to be included in the first place
$allowed = ['home', 'blog', 'gallery', 'catalog'];
$page = (in_array($page, $allowed)) ? $page : 'home';
echo file_get_contents('../pages/'.$page.'.php');

Command injection

Be careful when dealing with commands executing functions and data you don’t
trust.
exec('rm -rf '.$GET['path']);

Code injection

Code injection happens when malicious code can be injected in eval() function,
so sanitize your data when using it:
eval('include '.$_GET['path']);

Cross site request forgery (XSRF/CSRF)

Cross site request forgery or one click attack or session riding is an exploit where
user executes unwanted actions on web applications.

Public files

Make sure to move all your application files, configuration files and similar parts
of your web application in a folder that is not publicly accessible when you visit
URL of web application. Some file types (for example, .yml files) might not be
processed by your web server and user can view them online.
Example of good folder structure:
app/
config/
parameters.yml

106
src/
public/
index.php
style.css
javascript.js
logo.png
Configure web server to serve files from public folder instead of your application
root folder. Public folder contains the front controller (index.php). In case web
server gets misconfigured and fails to serve PHP files properly only source code
of index.php will be visible to public.
• More details is available in the dedicated FAQ: How to Use Configuration
in PHP Applications?

Passwords

When working with user’s passwords hash them properly with password_hash()
function.
• More details is available in “How to work with users’ passwords and how
to securely hash passwords in PHP?” FAQ.

Uploading files

A lot of security breaches happen where users can upload a file on server. Make
sure you go through all the vulnerabilities of uploading files such as renaming
uploaded file, moving it to publicly unaccessible folder, checking file type and
similar. Since there are a lot of issues to check here, more information is located
in the separate FAQ:
• How to securely upload files with PHP? FAQ.

Session hijacking

Session hijacking is an attack where attacker steals session ID of a user. Session


ID is sent to server where $_SESSION array gets populated based on it. Session
hijacking is possible through an XSS attack or if someone gains access to folder
on server where session data is stored.

Remote file inclusion

Remote file inclusion attack (RFI) means that attacker can include custom
scripts:

107
$page = $_GET['page'] ?? 'home'

require $page . '.php';


In above code $_GET can be set to a remote file http://yourdomain.tld/index.php?page=http://example.co
Make sure you disable this in your php.ini unless you know what you’re doing:
; Disable including remote files
allow_url_fopen = off
; Disable opening remote files for include(), require() and include_once() functions.
; If above allow_url_fopen is disabled, allow_url_include is also disabled.
allow_url_include = off

PHP configuration

Always keep installed PHP version updated. You can use versionscan to check
for possible vulnerabilities of your PHP version. Update open source libraries
and applications and maintain web server.
Here are some of the important settings from php.ini that you should check out.
You can also use iniscan to scan your php.ini files for best security practices.

Error reporting

In your production environment you must always turn off displaying errors
to screen. If errors occur in your application and they are visible to the
outside world, attacker can get valuable data for attacking your application.
display_errors and log_errors directives in php.ini file:
; Disable displaying errors to screen
display_errors = off
; Enable writing errors to server logs
log_errors = on
• More information in the How to show errors in PHP FAQ.

Exposing PHP version

PHP version is visible in HTML headers. You might want to consider hiding
PHP version by turning off expose_php directive and prevent web server to
send back header X-Powered-By:
expose_php = off

108
Remote files

In most cases it is important to disable access to remote files:


; disabled opening remote files for fopen, fsockopen, file_get_contents and similar function
allow_url_fopen = 0
; disabled including remote files for require, include ans similar functions
allow_url_include = 0

open_basedir

This settings defines one or more directories (subdirectories included) where


PHP has access to read and write files. This includes file handling (fopen,
file_get_contents) and also including files (include, require):
open_basedir = "/var/www/test/uploads"

Session settings

• session.use_cookies and session.use_only_cookies


PHP is by default configured to store session data on the server and a
tracking cookie on client side (usually called PHPSESSID) with unique ID
for the session.
; in most cases you'll want to enable cookies for storing session
session.use_cookies = 1
; disabled changing session id through PHPSESSID parameter (e.g foo.php?PHPSESSID=<session i
session.use_only_cookies = 1
session.use_trans_sid = 0
; rejects any session ID from user that doesn't match current one and creates new one
session.use_strict_mode = 0
• session.cookie_httponly
If the attacker somehow manages to inject Javascript code for stealing
user’s current cookies (the document.cookie string), the HttpOnly cookie
you’ve set won’t show up in the list.
session.cookie_httponly = 1
• session.cookie_domain
This sets the domain for which cookies apply. For wildcard domains you
can use .example.com or set this to the domain it should be applied. By
default it is not enabled, so it is highly recommended for you to enable it:
session.cookie_domain = example.com

109
• session.cookie_secure
For HTTPS sites this accepts only cookies sent over HTTPS. If you’re still
not using HTTPS, you should consider it.
session.cookie_secure = 1

Use HTTPS

HTTPS is a protocol for secure communication over network. It is highly rec-


ommended that you enable it on all sites. Read more about HTTPS in the
dedicated FAQ: How to Install SSL Certificate and Enable HTTPS.

What is next?

Above we’ve introduced many security issues. Security, attacks and vulnerabil-
ities are continuously evolving. Take time and check some good resources to
learn more about security and turn this check list into a habit:
• General:
– Awesome AppSec - A curated list of resources for learning about
application security.
– OWASP - The Open Web Application Security Project, organization
focused on improving security of software.
– Security Guide for Developers
– The Basics of Web Application Security, by Martin Fowler.
• PHP focused:
– PHP Manual - A must read security chapter in official documenta-
tion.
– Codecourse videos - Demos and advice on the most common PHP
security areas.
– DVWA, Damn Vulnerable Web Application - Example of unsecure
web application to test your skills and tools.
– OWASP PHP Security Cheat Sheet - Basic PHP security tips for
developers and administrators.
– Securing PHP - Website and books with basic topics and specific
cases in authentication/authorization and exploit prevention.
– SensioLabs Security - SensioLabs Security Advisories Checker for
checking your PHP project for known security issues
– The most forgotten web vulnerabilities - Recommended PDF article.
– websec.io - Dedicated to educating developers about security with
topics relating to general security fundamentals, emerging technolo-
gies and PHP-specific information.
• Tools:
– iniscan - A php.ini scanner for best security practices.

110
– Kali Linux - Penetration testing Linux distribution.
– Observatory by Mozilla - Online security checker.
– versionscan - PHP version scanner for reporting possible vulnerabili-
ties.
– Roave Security Advisories - This package ensures that your applica-
tion doesn’t have installed dependencies with known security vulner-
abilities.
– WebSecTools - List of useful web security related tools.
– OWASP Zed Attack Proxy - Free security tool, available also on
GitHub.

How to work with users’ passwords and how to


securely hash passwords in PHP?
When you must save user’s password in a database you should never ever
store them in plain text because of security precautions and privacy protec-
tion. Database where users’ passwords are stored might get compromised and
by hashing them at least there is another safety mechanism for not revealing
them to the attacker.
<?php

// plain text password example


$password = 'secretcode';
Cryptography is a large and quite complex field for a lot of people so a good
rule of a thumb would be to leave it to the experts.
One of the most used but wrong way of hashing password was once using md5()
which calculates md5 hash of a string. Hashing passwords with md5 (or sha1 or
even sha256) is note safe anymore because these hashes can get decrypted very
fast.
<?php

// plain text password


$password = 'secretcode';

// hash the password with md5


$md5 = md5($password);
Common solution to preventing decryption is using the salt.
<?php

// plain text password

111
$password = 'secretcode';

// add random number of random characters - the salt


$salt = '3x%%$bf83#dls2qgdf';

// hash salt and password together


$md5 = md5($salt.$password);
This is still not good enough though - Rainbow tables.

Right way of hashing passwords in PHP

Right way of hashing passwords is currently using latest PHP version and its
native passwords hashing API which provides an easy to use wrapper around
crypt function.
Example of PHP native password hashing API usage:
<?php

// plain text password


$password = 'secretcode';

$options = ['cost' => 12];


echo password_hash($password, PASSWORD_DEFAULT, $options);
In password_hash() function there are currently two types of algorithm
options available. PASSWORD_DEFAULT and PASSWORD_BCRYPT. Currently
PASSWORD_DEFAULT is PASSWORD_BCRYPT and as language and cryptog-
raphy progress there will be different types of algorithms supported.
PASSWORD_DEFAULT will get replaced with that new type of algorithm
(for example, Argon2). Good choice is to always use the PASSWORD_DEFAULT.
The database password’s field type should be varchar(255) for future proof
algorithm changes.
Using your own salt is not a very good option. Leave that to the experts as
well and use above bullet proof solution without setting your own salt. Salt is
randomly generated by default in password_hash() function.
Another option that is important to mention is the cost which controls the
hash speed. On servers with better resources cost can be increased. There is a
script for calculating the cost for your environment in the PHP manual. As a
good security practice try increasing this to higher value than the default 10.
Verifying passwords can be done with password_verify():
<?php

112
// this is the hash of the password in above example
$hash = '$2y$12$VD3vCfuHcxU0zcgDvArQSOlQmPv3tXW0TWoteV4QvBYL66khev0oq';

if (password_verify('secretcode', $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
Another useful function is password_needs_rehash() - which checks if given
hash matches given options. This comes handy in case of server hardware up-
grade and therefore increasing the cost option.
The hash string returned by password_hash() consists of the following parts:
$2y$10$VCbjoi9DnyQyVxf4/RRoFeyOCeMPnCitAG07ZRpivwglmpbP0jOdW
| | | |
| | | |_ password (length depends on algorithm)
| | |
| | |_ salt (22 characters)
| |
| |_ cost (2 characters)
|
|_ algorithm (length depends on algorithm)
So, you can extract raw password hash components like this:
$hash = '$2y$10$VCbjoi9DnyQyVxf4/RRoFeyOCeMPnCitAG07ZRpivwglmpbP0jOdW';
list(, $algo, $cost, $salt_and_password) = explode('$', $hash);
$salt = substr($salt_and_password, 0, 22);
$password = substr($salt_and_password, 22);
Or simply use password_get_info() to get more readable information.
$hash = '$2y$10$VCbjoi9DnyQyVxf4/RRoFeyOCeMPnCitAG07ZRpivwglmpbP0jOdW';
print_r(password_get_info($hash));

Output
Array
(
[algo] => 1
[algoName] => bcrypt
[options] => Array
(
[cost] => 10
)

113
Password hashing in older PHP versions (5.5 and below)

In case you’re still using some older PHP version, there is a way to secure
passwords securely. Since PHP version > 5.3.7 you can use PHP library pass-
word_compat. PHP library password_compat works exactly the same way as
does the native PHP password hashing API, so when you upgrade to latest PHP
you will not need to refactor your code.
For PHP version below 5.3.6 phpass might be a good solution, but try to avoid
these and use the native password hashing API.

Password hashing in open source projects

Some of the widely used PHP open source projects use different hashing al-
gorithms for passwords because they either support older PHP versions where
password_hash() wasn’t available yet or they already use the latest security
recommendations by PHP security experts:

Project Password hashing


CMS Airship Argon2i
Drupal SHA512Crypt with multiple rounds
Joomla bcrypt
Laravel bcrypt with other options
Symfony bcrypt with other options
Wordpress salted MD5

See also

• PHP.net passwords FAQ


• csiphp.com - Interesting blog post about encrypting passwords
• password-validator - PHP library that validates passwords against PHP’s
password_hash function using PASSWORD_DEFAULT. Will rehash when
needed, and will upgrade legacy passwords with the Upgrade decorator.
• securepasswords.info - A polyglot repo of examples for using secure pass-
words (typically bcrypt).
• How to Safely Store Your Users’ Passwords in 2016

What is SQL injection and how to prevent it?


When working with databases, one of the most common security vulnerabilities
in web applications is definitely SQL injection attack. Malicious users can insert

114
Figure 12: SQL injection

SQL query into the input data you’re using in your SQL queries and instead
unwanted behavior happens.

SQL injection example with PDO

// GET data is sent through URL: http://example.com/get-user.php?id=1 OR id=2;


$id = $_GET['id'] ?? null;

// You are executing your application as usual


// Connect to a database
$dbh = new PDO('mysql:dbname=testdb;host=127.0.0.1', 'dbusername', 'dbpassword');

// Select user based on the above ID


// bump! Here SQL code GET data gets injected in your query. Be careful to avoid
// such coding and use prepared statements instead
$sql = "SELECT username, email FROM users WHERE id = " . $id;

foreach ($dbh->query($sql) as $row) {


printf ("%s (%s)\n", $row['username'], $row['email']);
}
Just imagine worst case scenarios with injected SQL:

115
"'DELETE FROM users */"
How to avoid SQL injection in above example? Use prepared statements:
$sql = "SELECT username, email FROM users WHERE id = :id";

$sth = $dbh->prepare($sql, [PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY]);


$sth->execute([':id' => $id]);
$users = $sth->fetchAll();

mysqli example

When using MySQL database quite you can also use mysqli with prepared state-
ments, or mysqli_real_escape_string() function, however you can just use
more advanced PDO.
// get data is sent through url for example, http://example.com/get-user.php?id=1 OR id=2;
$id = $_GET['id'] ?? null;

// in your code you are executing your application as usual


$mysqli = new mysqli('localhost', 'db_user', 'db_password', 'db_name');

if ($mysqli->connect_error) {
die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
}

// bump! sql injected code gets inserted here. Be careful to avoid such coding
// and use prepared statements instead
$query = "SELECT username, email FROM users WHERE id = " . $id;

if ($result = $mysqli->query($query)) {
// fetch object array
while ($row = $result->fetch_row()) {
printf ("%s (%s)\n", $row[0], $row[1]);
}

// free result set


$result->close();
} else {
die($mysqli->error);
}
Let’s fix this with prepared statements. They are more convenient because
mysqli_real_escape_string() doesn’t apply quotes (it only escapes it).
// get data is sent through url for example, http://example.com/get-user.php?id=1 OR id=2;
$id = $_GET['id'] ?? null;

116
// in your code you are executing your application as usual
$mysqli = new mysqli('localhost', 'db_user', 'db_password', 'db_name');

if ($mysqli->connect_error) {
die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
}

// bump! sql injected code gets inserted here. Be careful to avoid such coding
// and use prepared statements instead
$query = "SELECT username, email FROM users WHERE id = ?";

$stmt = $mysqli->stmt_init();

if ($stmt->prepare($query)) {
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_array(MYSQLI_NUM)) {
printf ("%s (%s)\n", $row[0], $row[1]);
}
}

See also

Other useful reading to check out:


• OWASP
• SQL injection - a community paradoxon
• Bobby Tables - A guide to preventing SQL injection.

How to securely upload files with PHP?


Uploading files in PHP is achieved with move_uploaded_file() function.
The HTML form for uploading single or multiple files must include the
enctype="multipart/form-data" attribute. Use the POST method:
<form method="post" enctype="multipart/form-data" action="upload.php">
File: <input type="file" name="pictures[]" multiple="true">
<input type="submit">
</form>
And the PHP upload.php script looks like the following:

117
<?php

foreach ($_FILES['pictures']['error'] as $key => $error) {


if ($error == UPLOAD_ERR_OK) {
$tmpName = $_FILES['pictures']['tmp_name'][$key];
// basename() may prevent directory traversal attacks, but further
// validations are required
$name = basename($_FILES['pictures']['name'][$key]);
move_uploaded_file($tmpName, "/var/www/project/uploads/$name");
}
}
Don’t stop here just yet and continue reading! The uploaded files must be
validated for security purposes. A lot of hacks can happen with not secured
uploading. Imagine malicious attacker uploads evil.php which is publicly ac-
cessible over https://example.com/uploads/evil.php.

Validation

Always make sure to implement all the server side validations for security mea-
sures and understand the security vulnerabilities behind them.

Directory traversal

To avoid the directory traversal (a.k.a. path traversal) attack use basename()
like shown above or even better rename the file completely like in the next step.

Rename uploaded files

Renaming file avoids duplicate names in the uploaded folder and also avoids di-
rectory traversal attacks. In case you might need the original file name, you can
store the file name in database. For example, renaming file with microtime()
and some random number:
$uploadedName = $_FILES['upload']['name'];
$ext = strtolower(substr($uploadedName, strripos($uploadedName, '.')+1));

$filename = round(microtime(true)).mt_rand().'.'.$ext;
You can also use hashing functions like hash_file(), sha1_file() to build file
name. This method can save some storage spaces when different users upload
the same file.
$uploadedName = $_FILES['upload']['name'];
$ext = strtolower(substr($uploadedName, strripos($uploadedName, '.')+1));

118
$filename = hash_file('sha256', $uploadedName) . '.' . $ext;

Check file type

Instead of relying on file extension, you can get a mime type of a file with
finfo_file():
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type extension
echo finfo_file($finfo, $filename);
finfo_close($finfo);
For images more reliable but still not good enough check in PHP is with
getimagesize() function:
$size = @getimagesize($filename);
if (empty($size) || ($size[0] === 0) || ($size[1] === 0)) {
throw new \Exception('Image size is not set.');
}

Check file size

To limit or check the uploaded file size you can check the $_FILES['files']['size']
and the errors UPLOAD_ERR_INI_SIZE and UPLOAD_ERR_FORM_SIZE:
if ($_FILES['pictures']['size'] > 1000000) {
throw new RuntimeException('Exceeded filesize limit.');
}

Storing uploads to private location

Instead of saving uploaded files to a public location available at https://example.com/uploads,


storing them in a publicly unaccessible folder is a good practice. To deliver
these files so called proxy scripts are used.

Client side validation

For better user experience HTML offers accept attribute to limit the file types by
the extension or mime type in the HTML, so user can see the validation errors
on the fly and selects only allowed types of files in their browser. However
browser support is limited at the time of this writing. Keep in mind that client
side validation can be bypassed by hackers in no time. Server side validation
steps explained in previous steps is the more important validation to use.

119
Full example

Let’s take all of the above into consideration and look at some very simple
example:
// check if we have file upload
if (isset($_FILES['upload']) && $_FILES['upload']['error'] == UPLOAD_ERR_OK) {
// Be sure we're dealing with an upload
if (is_uploaded_file($_FILES['upload']['tmp_file']) === false) {
throw new \Exception('Error on upload: invalid file definition');
}

// Rename uploaded file


$uploadName = $_FILES['upload']['name'];
$ext = strtolower(substr($uploadName, strripos($uploadName, '.')+1));
$filename = round(microtime(true)).mt_rand().'.'.$ext;

move_uploaded_file($_FILES['upload']['tmp_file'], __DIR__.'../uploads/'.$filename);
// Insert it into our tracking along with the original name
}

Server configuration

Server side validation mentioned above can be still bypassed by embedding


custom code inside the image itself with tools like jhead and the file might be
run and interpreted as PHP.
That’s why enforcing the file types should be done also on the server level.

Apache

Make sure Apache is not configured to interpret multiple files as same. For
example, images being interpreted as PHP files. Use the ForceType directive to
force the type on the uploaded files.
<FilesMatch "\.(?i:pdf)$">
ForceType application/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
or in case of images:
ForceType application/octet-stream
<FilesMatch "(?i).jpe?g$">
ForceType image/jpeg
</FilesMatch>

120
<FilesMatch "(?i).gif$">
ForceType image/gif
</FilesMatch>
<FilesMatch "(?i).png$">
ForceType image/png
</FilesMatch>

Nginx

On Nginx you can use the rewrite rules, or use the mime.types configurations
file provided by default.
location ~* (.*\.pdf) {
types { application/octet-stream .pdf; }
default_type application/octet-stream;
}

See also

• How to Securely Allow Users to Upload Files


• PHP Image Upload Security: How Not to Do It
• Related FAQ: How to Increase the File Upload Size in PHP?
• PHP Manual: Handling file uploads
• brandonsavage/Upload - standalone PHP upload component with valida-
tion and storage strategies.
• Uploading files with Laravel framework
• Uploading files with Symfony framework
• ralouphie/mimey - PHP package for converting file extensions to MIME
types and vice versa.
• phpMussel/phpMussel - PHP-based anti-virus anti-trojan anti-malware
solution capable of scanning file uploads and with some simple upload
controls included.

Configuration in PHP applications

What is configuration?

Applications require a centralized place where settings are stored. All the values
stored here are required to configure the behavior of the application and to define
the resources for other entities of the application. These include usernames,
passwords, database access info, API keys, email settings and similar.

121
The main purpose of configuration is the integrity of the stored values, the
reachability of values for a certain domain, and the static behavior.
Configuration is the domain-aware orchestration of static settings, which
shouldn’t change between a request and a response.

What should a configuration implementation cover?

Configuration is a separate concern that combines multiple responsibilities into


one implementation. All these responsibilities should have its own classes due
to the Single responsibility principle.

Distribution (mandatory)

One of the configuration responsibilities is distribution. Distribution covers the


reachability of the values in a configuration implementation. It ensures the
availability management of configuration domains inside the configuration. To
avoid any side effects: Distribution should be implemented immutable.
For example, database settings are grouped into a database domain to ensure
that the database object always contains only database related settings.

Validation and sanitization (mandatory)

Another responsibility is validation and sanitization. Both cover the integrity


of values in a configuration implementation.
For example, database settings have different types of settings. Validation en-
sures that the given values fit their required types. Sanitization ensures that
resources are converted to their required types prior to validation.

Zero-Configuration (optional)

The responsibility of Zero-Configuration is an optional responsibility that au-


tomatically enforces default values to a configuration. The reason behind this
approach is to reduce the effort of proper application configuration.
For example, database settings are traditionally limited to the hostname, port
and the credentials that are required to authenticate to the database service.
The Zero-Configuration approach enforces the default values. In case of MySQL
database:
hostname: localhost
port: 3306

122
With these default values in mind, defining hostname or port is not needed in
common cases, when the targeted service is located at localhost and listening
on port 3306.

Caching (recommended)

The responsibility of caching is a recommended responsibility that should be


always implemented in a common web application to ensure validity, integrity
and availability in the fastest way.

Formats

Application configuration can be defined in all sorts of formats and places. From
the regular PHP files, to other file formats such as YAML, INI, XML, JSON,
NEON and similar. It can be defined even in the database.
The format of the defined application depends on the complexity of what must
be configured and the wanted complexity of the configuration definition. Some
configuration formats are limited to a specific set of definition utilities, other
formats are open side effects to the user land that may have an impact to the
configuration integrity.
Choose the configuration format based on these suggestions and what is suitable
for your project case or better readability for you.

PHP files

<?php
// config/config.php

$configuration = [
'database' => [
'hostname' => 'localhost',
'port' => 3306
'name' => 'db_name',
'username' => 'db_username',
'password' => 'db_secret_password',
]
];
PHP files are actually scripts that define an object, array or a mixture of both.
The major benefit of this format is the validity of the file format which is directly
enforced by the PHP parser. If opcode caching is available, this format will be
also pretty fast.

123
The major downside of this format is the abuse possibility. You can quickly
invalidate the static state of a configuration definition by utilizing conditions
or other stuff that might change the returning value which is sensitive to the
environment or request.

YAML

# config/config.yml
database:
hostname: 'localhost'
port: 3306
name: 'db_name'
username: 'db_username'
password: 'db_secret_password'
YAML is a format that unifies the benefits of JSON and XML into a single
but different format. YAML is both, a format that is intended to act as a data
notation and as a file format to define documents. YAML has also a lot of
different features that are not common to documents or object notations (entity
linking). YAML supports widely the same syntax as JSON does.
To parse YAML files there are available 3rd party libraries such as Symfony
Yaml Component, or the Yaml PHP Extension, which isn’t bundled with PHP.

INI

; config/config.ini
[database]
database_hostname=localhost
database_port=3306
database_name=db_name
database_username=db_username
database_password=db_secret_password
INI files define data in a simple way. The INI format is less complex than other
formats. Whatever you want to assign to a field would be associated as it would
be associated in PHP. INI files can have groups as well, but does not support
higher structs (arrays, objects).
Parsing of INI files can be done with PHP parse_ini_file() and pase_ini_string()
functions.

XML

<?xml version="1.0" encoding="UTF-8"?>


<configuration>

124
<database default="true">
<server hostname="localhost" port="3306">
<environment dbname="db_name">
<auth username="db_username" password="db_secret_password" />
</environment>
</server>
</database>
</configuration>
XML documents relay on specific entities and have a Document Object Model
that requires a lot of knowledge to define proper documents. XML files are
prone to failure due to its high efforts to define the document.
The major benefit of XML documents is they can easily transported to other
formats or structures using XSLT or traditional scripts. XML is the most flexible
format because of the descriptive nature of XML.
The major downside of XML is, it is not intended to be human readable as other
formats are.
There are multiple ways to parse XML format. For example, there is XML
Parser extension enabled by default.

JSON

{
"database": {
"hostname": "localhost",
"port": "3306",
"name": "db_name",
"username": "db_username",
"password": "db_secret_password"
}
}
JSON is actually an Object Notation not a real file format. Since composer
enters the PHP universe, JSON is the considered data structure for statically
applied configuration in files with the file extension: .json.
The major benefit of JSON is, it remains always to the same syntax and
does restrict the configuration definition context to strings, integers, floats and
booleans.
The major downside of JSON is, it is an object notation. No inline documen-
tation allowed and you actually configure your application with a format that
was intended to be used as to transport data from end-point to end-point.
To parse JSON format, there is available json_decode().

125
NEON

# config/config.neon

database: mysql(
hostname=localhost,
port=3306,
name=db_name,
username=db_username,
password=db_secret_password
)
NEON is a YAML derivate invented by the guys of the Nette Framework, that
adds entities to the definition model of YAML.
Package nette/neon can parse NEON files.

Performance

Configuration formats must be processed by PHP so various formats can have


different performance. It may seem that the fastest way is to use PHP format
since PHP understands it by default, however you can use different caching
strategies when parsing configuration files to PHP understandable formats (PHP
files with arrays or classes).
The performance of configurations depends on the implementation not on the
format utilized in general. It does not matter if you use XML, YML, NEON
or plain PHP when the application utilizes a cache for configuration where the
distribution responsibility products are cached. You should always consider a
caching mechanism when implementing configurations into your application.
There are 2 well known caching approaches:

Active caching
Active caching observes always configuration files each time your application is
bootstrapped. Once a configuration file has changed, the configuration cache
invalidates and a rebuild process for the cache will be executed.
Active caching raised performance peeks to your application whenever the con-
figuration cache invalidates a segment (domain) of your configuration. Active
caching is the caching mechanism to choose when performance peaks do not
deal damage to the overall application performance (small applications with
less traffic).

126
Passive caching
Passive caching relays on maintainer actions to enforce the cache building for
the application after changes are made to the configuration files.
Passive caching ensures that no performance peeks hit your application. The
built configuration cache is always committed to the server by the maintainer
of the application. Passive caching is the caching mechanism to choose when
aiming for a very balanced application performance (applications with high
traffic).

Environments

Applications are used in different environments (development, production, stag-


ing, testing, beta, etc.). When developing an application, the configuration is
different from the configuration defined on the production server. To approach
this effectively, best practice is to have different configuration files for each
environment and add/upload them to the project separately from the secure
location or by using one of the deployment tools which can do that.
You can also define default values for all environments that get overwritten when
deploying or installing application locally.
# config/config.yml.dist
database:
hostname: 'localhost'
port: 3306
name: 'project'
username: 'root'
password: ~
Many projects use the practice of adding dist to the filename which means
the default configuration that comes with the distribution. For example, the
hostname defaults to localhost, port defaults to MySQL default port 3306 etc.
The special character tilde - ~ above notes the null value in YAML. All these
settings can be overridden and set in your application in config/config.yml
when installing.

Types of configuration

Types of application configuration can be structured into the following types:


• Infrastructure configuration
These depend on the environment where the application is running and
don’t define the behavior of the application directly. This includes security
credentials, such as database passwords, API access keys and similar.

127
• Application configuration
These define the behavior of the application and depend on the environ-
ment where the application is running. For example, the debugging turned
on or off, database type (for example, you can use different database type
in testing), locale settings and similar.
– Fixed application configuration
These don’t change very often during the certain application version.
For example database type, number of items shown per page etc.
– Variable application configuration
These change more frequently in certain application version. For
example user settings (showing/hiding signature in forum topics, de-
fault currency used in e-store for signed in users), settings meant
to be changed by non-developers (contact emails, Google sitemap
settings) etc.

Bad practices

Using PHP constants to define configuration values might seem like a good
choice because of the global state:
<?php
// config/config.php

define('DATABASE_NAME', 'db_name');
define('DATABASE_USERNAME', 'db_username');
define('DATABASE_PASSWORD', 'db_password');
However this is not a good practice for the following reasons:
• You are polluting the global namespace and can have compatibility issues
from other libraries or code that might define same constant.
• Their value cannot be changed in the code, which might have issues when
testing code.
• Difficult code refactoring in case they were used in multiple places
• Limited set of types available (only boolean, integer, float, string, array
and resource).
Some of the limitations mentioned above can be avoided by using class constants.
This should be used only for configuration values that never or very rarely change
in certain application version. For example, maximum number of elements
shown per page and similar:
<?php

class Article

128
{
const MAX_ITEMS_PER_PAGE = 10;

//...
}

$limit = Article::MAX_ITEMS_PER_PAGE;
Limitation of this is still difficult changing of these values in testing environment
for example.

Singleton pattern

Another approach for storing configuration values is to use singleton pattern


because it introduces global state and simple access to the configuration values
in the application:
<?php

class Config
{
/**
* @var Config
*/
private static $instance;

/**
* @var array
*/
private static $values = [];

/**
* Instantiation can be done only inside the class itself
*/
private function __construct() {}

/**
* @return Config
*/
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new self();
}

return self::$instance;

129
}

/**
* Set configuration value by key.
*
* @param string $key
* @param mixed $value
*/
public static function set($key, $value)
{
self::$values[$key] = $value;
}

/**
* Get configuration value by key.
*
* @param string $key
* @return mixed
*/
public static function get($key)
{
if (isset(self::$values[$key])) {
return self::$values[$key];
}

return null;
}

/**
* Cloning singleton is not possible.
*
* @throws Exception
*/
public function __clone()
{
throw new Exception('You cannot clone singleton object');
}
}

$config = Config::getInstance();
$config->set('database_username', 'db_username');
However using singleton pattern reduces testability as well. Instead, a better
practice is to use the dependency injection, container and repository patterns.

130
Misconception of configurations

Everything that is not static in the moment the configuration is defined should
not be considered as configuration. You should always utilize the format that
allows you to define exempts (like entities in NEON) that provides a structure
that allows the implementation to fit the setting to an environment’s sensitive
state.
A neon example:
# general
debug: whenIn(server=REMOTE_ADDR, [::1, 127.0.0.1], if=true, else=false)

environment: sapi({
php_cli: cli
}, default=www);
Translation data should not be part of the configuration, no matter which kind
of translation distribution format was chosen. Translations always relay on a
non static part.

Security

When working with application configuration, never expose sensitive configu-


ration files in public. To avoid that, place the configuration files outside the
publicly accessible document root on the server, so they are not accessible over
web https://example.com/config/config.yml.
Folder structure could be in this case the following:
project/
public/
index.php
css/
js/
images/
config/
config.yml
src/
vendor/
The public folder in this case is the document root folder which is accessible
over web https://example.com.

131
Environment variables

A good practice is to use environment variables for configuration such as security


credentials (database access, API keys, etc.). Environment variables are special
system variables defined on the system level.
First a bit of an introduction into PHP environment variables and some caveats
when working with them.
On Apache servers environment variables can be defined in the VirtualHost
configuration with the special SetEnv directive of mod_env:
<VirtualHost *:80>
ServerName example.com
DocumentRoot "/var/www/project/public"
DirectoryIndex index.php index.html
SetEnv APP_DATABASE_USERNAME db_username
SetEnv APP_DATABASE_PASSWORD db_secret_password

<Directory "/var/www/project/public">
AllowOverride All
Allow from All
</Directory>
</VirtualHost>
On Nginx servers environment variables can be set with fastcgi_param direc-
tive in configuration file where the fastcgi_params is being included:
# /etc/nginx/sites-available/example.com

location ~ \.php$ {
#...
include fastcgi_params;
fastcgi_param APP_DATABASE_USERNAME db_username;
fastcgi_param APP_DATABASE_PASSWORD db_secret_password;
#...
}
When your application is running in PHP CLI (which does not use web server),
environment variables must be set also with export (for Linux servers):
export APP_DATABASE_USERNAME="db_username"
export APP_DATABASE_PASSWORD="db_secret_password"
In PHP environment variables can be than accessed with getenv():
<?php
// config/config.php

$configuration = [

132
'database_username' => getenv('APP_DATABASE_USERNAME'),
'database_password' => getenv('APP_DATABASE_PASSWORD'),
];

PHP dotenv

A very useful PHP library that adds best practices to your application when
working with environment variables for configuration is PHP dotenv.
After installation with Composer:
composer require vlucas/phpdotenv
Add the .env file to the root of your project:
APP_DATABASE_USERNAME="db_username"
APP_DATABASE_PASSWORD="db_secret_password"
In PHP the configuration values can be than accessed like environment variables
explained above:
<?php

require __DIR__.'/../vendor/autoload.php';

$dotenv = new Dotenv\Dotenv(__DIR__.'/..');


$dotenv->load();

$dbUsername = getenv('APP_DATABASE_USERNAME');
Worth noting is that environment variables are still exposed on the system level.
Be careful to not output them. For example, with phpinfo(). Important to
understand is, when the environment variables are useful for your case scenario
and when to use other tools like Vault, Chef or similar.

Git repositories

When committing code to the source control (Git), avoid adding configuration
files to the commits. In case of Git, ignore the configuration files containing
sensitive configuration values with .gitignore:
#.gitignore file which omits committing config.php file to the Git repository
/config/config.php

133
Encapsulation

The infrastructure configuration don’t change during the running of the appli-
cation. In case you don’t have simple access to the production environment
infrastructure configuration values (database credentials) but still need to de-
velop application independently and frequently add more infrastructure related
configuration in the next version of the application, you can use encapsulation:
<?php
// config/database.php

return [
'database_name' => 'db_name',
'database_username' => 'db_username',
'database_password' => 'db_secret_password',
];
And use it in your application configuration with the rest of the infrastructure
configuration:
<?php
// config/config.php

return array_merge([
'fb_app_id' => 123456,
'fb_app_secret' => 'facebook_app_secret',
],
require(__DIR__.'/database.php')
);

Configuration stored in the database

Some configuration values that often change or are meant to be changed by


non-developers, can be defined in the database so they can be easily changed
over the UI.
There are multiple different approaches you can look into. From using key-value
storages to designing the database schema for these tables accordingly for the
current project:
• Key-value table (column types can be json, array or similar for different
configuration types)
• EAV (entity-attribute-value)
• Configuration in the same table as the other entities (for example, user
settings)
• … and many other ideas

134
Serialization is useful for storing values without losing their type and structure.
Above PHP configuration example can be represented in serialized format using
the serialize():
a:3:{s:13:"database_name";s:7:"db_name";s:17:"database_username";s:11:"db_username";s:17:"da

SQLite

SQLite is file-based fast. It is also valuable as a configuration resource and


therefore valuable to store configurations.
The major benefit of SQLite is, its table can contract value types, which exclude
the need of validating the types of configuration values. Those value types are
enforced inbound and output to the database.
The major downside of SQLite is, it is a binary format and not maintainable
without an SQLite client.

How to use configuration in PHP application?

Many times you might be tempted to access the configuration values in the
application code directly:
<?php

class Database
{
private $name, $username, $password;

/**
* Constructor.
*/
public function __construct()
{
$this->name = getenv('APP_DATABASE_NAME');
$this->username = getenv('APP_DATABASE_USERNAME');
$this->password = getenv('APP_DATABASE_PASSWORD');
}

//...
}
Issue with such approach is difficult maintaining of the code when scaling and
testing. The other not good enough step is injecting the configuration handler
directly in the needed class:

135
<?php

class Config
{
/**
* @var array
*/
private $values;

/**
* Constructor.
*
* @param array $values
*/
public function __construct($values)
{
$this->values = $values;
}

/**
* Get configuration value by key.
*
* @param string $key
* @return mixed
*/
public function get($key)
{
return $this->values[$key];
}
}

class Database
{
private $name, $username, $password;

/**
* Constructor.
*
* @param Config $config
*/
public function __construct($config)
{
$this->name = $config->get('database_name');
$this->username = $config->get('database_username');
$this->password = $config->get('database_password');
}

136
}

// ...

$config = new Config(require(__DIR__.'/../config/config.php'));

$database = new Database($config);


Instead, you should inject the needed configurations separately to the separate
adapter class:
<?php

class DatabaseAdapater
{
protected $inhibitor = null;
protected $instance = null;

private $name;
private $username;
private $password;
private $hostname = '127.0.0.1';

/**
* Constructor.
*/
public function __construct()
{
$this->inhibitor = Closure::bind(
function ($name = null, $username = null, $password = null, $hostname = null): P
return new PDO(
'mysql:dbname='.($name ?? $this->name).';host='.($hostname ?? $this->hos
$username ?? $this->username,
$password ?? $this->password
);
},
$this,
DatabaseAdapter::class
);
}

/**
* Set database name.
*
* @param string $name
*/
public function setName(string $name)

137
{
$this->name = $name;
}

/**
* Set database username.
*
* @param string $username
*/
public function setUsername(string $username)
{
$this->username = $username;
}

/**
* Set database password.
*
* @param string $password
*/
public function setPassword(string $password)
{
$this->password = $password;
}

/**
* Set database hostname.
*
* @param string $hostname
*/
public function setHostname(string $hostname)
{
$this->hostname = $hostname;
}

/**
* Get Database adapter instance.
*
* @return DatabaseAdapter
*/
public function getInstance(): PDO
{
if ($this->instance instanceof PDO) {
return $this->instance;
}

return $this->instance = call_user_func($this->inhibitor);

138
}
}

class Database
{
/**
* @var DatabaseAdapter
*/
private $adapter;

/**
* Constructor.
*
* @param DatabaseAdapter $adapter
*/
public function __construct(DatabaseAdapter $adapter)
{
$this->adapter = $adapter;
}
}

$adapter = new DatabaseAdapter();


$adapter->setName($config->get('database_name'));
$adapter->setUsername($config->get('database_username'));
$adapter->setPassword($config->get('database_password'));
$db = $adapter->getInstance();

Conclusion

Configuration should always be validated to ensure its integrity. The perfor-


mance of configuration is not based on the size or the format in which the
configuration has been defined in. It is based on the mechanism that aggregates
the configuration distribution to the application. Always cache a process that
might result in performance peaks, choose the right caching mechanism for your
application and configuration size.

See also

More resources you should look into:


• Nette Bootstrap - Configuration component from Nette Framework.
• PHP dotenv - PHP library which loads environment variables.
• Respect/Config - A tiny, fully featured dependency injection container as
a DSL.

139
• Symfony Config component
• Twelve Factor App - Configuration chapter of the Twelve Factor App
book.
• werx/config - Use environment-specific configuration files in your app.
• Zend Config

How to protect and hide PHP source code?


In the time of open-source there are multiple benefits of making your code
available to all. However when deploying or selling your PHP code to a client
you might want to protect and hide it because of different business reasons or
security.
There are multiple approaches to check based on the use cases:
• Obfuscation - makes code difficult to read by a human in order to hide
its logic or purpose. In most cases the reverse-engineering of such code is
still possible so obfuscation doesn’t provide proper code protection if you
need it.
• SaaS - Software as a service is code licensing approach where the code
is accessed from a server based on licenses and subscriptions to enabled
users. Consider this kind of way if you want to make sure that the code
is not available to end-users or that it is used only on request.
• License agreements and contracts are the usual approach to make agree-
ments between coders with clients.

See also

• PHP Encoder by ionCube - Proprietary PHP encoder.


• Zend Guard - Proprietary protector of applications with PHP encoding

How to install SSL certificate and enable


HTTPS?
HTTPS is a protocol for secure communication over network. It is recommended
to use it on all sites these days for security reasons, specially when dealing with
logins, e-commerce and similar vulnerable data transactions.
SSL certificates also seals the ownership of webpages and the responsible in-
stances for the domain that utilizes the SSL certificate.
SSL adds both, security and authenticity, to your website or web application.

140
See also

Some recommended resources to check:


• Let’s Encrypt - Free SSL/TLS certificates (US based Certification Author-
ity).
• Certbot - Automatically enable HTTPS on hosts with console access to
your website with EFF’s Certbot, deploying Let’s Encrypt certificates.
• SSL Server Test - Online tool to test SSL on a webserver.
• Pentest Cheatsheet - Penetration Tester’s Checklist for SSL.

Encryption, hashing, encoding and obfuscation


The following terms have different meaning and are often confused. Cryptog-
raphy is a very complex and large field, and it is good to know more about
it, but for professional reinventing of cryptographic algorithms, it’s best left to
professionals only.
Encryption changes data in such a way that it can be converted back to its
original state when the correct encryption key is known.
Hashing changes data in a way that it can NOT be converted back to ts
original state. Hashing is commonly used for verifying passwords (in such cases,
an application doesn’t need to know the actual password to operate normally).
Encoding has nothing to do with cryptographic algorithms directly. Encoding
is transforming data so that it can be properly read by different systems and
applications.
Obfuscation is changing data so that it becomes more difficult to read or to
be reverse engineered.

See also

• Paragonie Blog
• How to Work With Users’ Passwords and How to Securely Hash Passwords
in PHP?
• Obfuscation (software)

What is a PHP framework and which one should


I learn and use?
A framework is a tool to help you develop applications faster and better. It
is a reusable set of libraries and/or classes. They usually define default folder

141
Figure 13: PHP Frameworks

142
structure of a project.
There are many existing, well established and secure open source frameworks
with large communities behind them. Rather than reinventing the wheel, many
developers use them to build web applications. There is NO best and NO
official PHP framework, because different purposes and different projects require
different tools and approaches.
Using established, existing open source frameworks is strongly advised when
working in a team. A framework can provide developers with a common same
set of standards and with better interoperability for when they build applications
together.

Which framework should you learn?

Before diving into a PHP framework, get familiar with some advanced concepts
such as OOP, design patterns, ORM, authentication, MVC (model view con-
troller), etc. For bigger projects, using a popular open source framework instead
of a custom framework and instead of procedural programming is advised.
Before understanding modern open source PHP frameworks, check out Com-
poser; A dependency manager for PHP.
In your career path, you will not need to know all of them, but you should learn
how to use few of the frameworks that are widely used in the industry or that
are important to you. Organizations and companies are always moving towards
modern, popular established frameworks, so predicting which framework will
get you a job in the PHP market today is a task for a prophet or a fortune
teller, and it is therefore almost impossible.
You can check the popularity trends in PHP community and check the most
popular ones (according to the stars on GitHub), but don’t get fooled by such
comparison charts. Each organization can move towards something else sooner
or later.
Learning some complex PHP frameworks can have a steep learning curve.
According to the architecture the framework itself is built upon, there are three
major types of frameworks that we will use to categorize them in this FAQ:

Component frameworks

Component frameworks are built and decoupled into separate components that
you can use in your application independently of other components. You can
just use some components or all of them. Most of component frameworks can
also be a full stack framework (described in the next section) at the same time.
• Aura

143
• Kohana
• Laravel
• Nette
• Symfony
• Zend Framework

Full stack frameworks

Full stack framework includes everything you need to develop an application in


one package. Decoupling of components is mostly not possible.
• Agile Toolkit
• CakePHP
• CodeIgniter
• Cygnite Framework
• FuelPHP
• Jelix
• Joomla Framework
• Lithium
• Opulence
• PHPixie
• Phalcon
• Phprest
• PPI
• Prado
• Simple MVC Framework
• Swoole
• Typo3 Flow
• Webiny
• Yaf - PHP framework written in C and built as an PHP extension.
• Yii

Micro-frameworks

A micro-framework holds a simple core with a very lightweight infrastructure


of classes and libraries. The main purpose of micro-frameworks is building
applications quickly while still keeping lightning fast performance speed and a
small footprint.
• Apigility - Micro-framework based on Zend Framework.
• Bullet PHP
• Dispatch
• FatFree
• Flight
• Flint - Micro-framework built on top of Silex.

144
• Horus
• Kraken - Distributed and async PHP framework.
• Lumen - Micro-framework by Laravel.
• MicroMVC
• Phlyty - Micro-framewok written using ZF2 components.
• Proton - StackPHP-compatible micro-framework.
• Silex - Micro-framework based on Symfony2 components.
• Slim
• Yolo

Miscellaneous

• API Platform - API-first web framework on top of Symfony with JSON-


LD, Schema.org and Hydra support.
• Medoo - PHP Database Framework.
• Zend Expressive - Minimalist PSR-7 middleware framework for PHP.
All the popular ones that we have encountered in this group are listed above in
alphabetical order.

Other resources

• Why all PHP frameworks suck? - PHP frameworks criticism by Rasmus


Lerdorf on phpclasses.org.
• Frameworks inside communities: The war of “best” - Blog post about the
“best” framework.

Related FAQs

• How to make your own PHP framework?

How to make your own PHP framework?


Building your own framework can be useful for the following reasons:
• You can learn a lot - advanced design patterns, concepts and software
architecture.
• You know exactly what certain parts of your code do without learning
from the documentation of others.
However, on the PHP market there are many very high quality open source
frameworks that many projects and organizations use to build software faster
and better. Picking an established open source framework has its benefits:

145
• When working in a team, people that already know the open source frame-
work used by a project can join the project faster.
• Better quality and a lot of bugs that have been identified and fixed, that
your custom framework hasn’t been tested for in a many projects yet.

What knowledge you will need to create a decent frame-


work?

For creating a framework you will have to know OOP, design patterns, ORM,
authentication, MVC (model view controller) and other advanced concepts.

See also

Here are listed some useful resources and tutorials that can also help you create
your own modern and quality PHP framework.
• Building your own framework on top of Symfony components - Build a
modern PHP framework on top of quality Symfony components.
• Frameworkless - Tutorial how to create custom framework with Composer
and PHP packages and components.
• No Framework tutorial
• PHP Frameworking - Introduction to frameworks and how to create your
own framework.

CakePHP framework
CakePHP is a MVC Rapid Development Framework for PHP.

See also

• Awesome CakePHP - A curated list of amazingly awesome CakePHP plu-


gins, resources and shiny things.
• Friends of CakePHP - Group of dedicated CakePHP developers working
together to provide the CakePHP community with high caliber CakePHP
plugins and resources.

CodeIgniter framework
CodeIgniter is a powerful PHP framework with a very small footprint, built for
developers who need a simple and elegant toolkit to create full-featured web

146
applications.
CodeIgniter has a lean MVC framework, with enough capabilities to improve
productivity, while providing for third-party addons/plugins for additional func-
tionality.

See also

• Documentation - CodeIgniter User Guide.


• Github - Codeigniter Repo
• Download- Codeigniter Download Link
• Forum-Support & Discuss

Laravel framework
Laravel is popular and simple to use component based PHP framework.

See also

Some useful resources to check when learning and working with Laravel:
• Awesome Laravel - A curated list of bookmarks, packages, tutorials, videos
and other cool resources from the Laravel ecosystem.
• Laracasts - Laravel video tutorials, free and paid.
• Laravel News

Symfony framework
Symfony is a set of reusable PHP components and a framework.
Best way to get to know Symfony is to go through a quick tour - four chapters,
each 10 minutes long. After that, reading the documentation is advised and is
the best way to learn it thoroughly.
Symfony uses bundles for applications and to extend and reuse functionality
in them. A large and vibrant community that has evolved around Symfony
provides bundles for almost anything. They can be found at KpnBundles.
You can also get certified or meet the community at one of the Symfony events.

147
See also

Useful resources and tutorials when working with Symfony:


• Awesome Symfony - A list of awesome Symfony bundles, utilities and
resources.
• Knp University - PHP and Symfony Tutorials (paid and free).
• Screenfony - Symfony tutorials (paid).
• Symfony2cheatsheet - Symfony cheatsheet.
• Working with Symfony 2 - Tuts+ - A video course about building appli-
cations in Symfony.
• Symfony Tutorial - Category for Symfony Tutorial.
• Symfony Finland - PHP, Symfony and web development articles.

Yii framework
Yii is a high-performance PHP framework.

Resources

• Documentation

See also

• Introduction to the Yii Framework


• How to Program With Yii2
• Yii2 Developer Exchange
• Yii Tutorials

Zend framework
Zend Framework - Enterprise and component based PHP Framework from Zend.

See also

• Documentation - Zend Framework 2 programmer’s reference guide.


• Zend Framework Certification

148
Writing quality code and code analysis
Beside writing tests, there are more factors that affect the quality of your code.
Let’s check some tools for PHP that can improve your code quality.

PhpMetrics

Figure 14: PhpMetrics

PhpMetrics is a very convenient static analysis tool for your code and your PHP
projects.
It can be installed with Composer or by downloading phar:
composer global require 'halleck45/phpmetrics'

149
phpmetrics --report-html=myreport.html /path/of/your/sources
PhpMetrics can even interact with Jenkins and Sonar.
After running PhpMetrics from terminal you get an HTML file that looks some-
thing like this:

Figure 15: PhpMetrics Report

Some examples of PhpMetrics reports:


• CodeIgniter 3.0 PhpMetrics report
• Symfony 2.6 PhpMetrics report

See also

Other useful tools to check out:


• PHP Parser - This is a PHP 5.2 to PHP 7.1 parser written in PHP. Its
purpose is to simplify static code analysis and manipulation.
• PHP QA tools - List of PHP Quality Assurance tools
• Jenkins PHP - Template for Jenkins Jobs for PHP Projects
• PHP Mess Detector - User friendly and easy to configure frontend for the
raw metrics measured by PHP Depend
• PHPCheckStyle - open-source tool that helps PHP programmers adhere
to certain coding conventions
• Qafoo Quality Analyzer - Tool helping us to analyze software projects.

150
How to test PHP code?
Testing code is an important part of development and should not be avoided. It
adds extra time to development but it also improves code quality and saves you
more time when you’re adding new features, or refactoring your code without
breaking something.
You’re testing your code already between the development itself without maybe
realizing. When you add some part of code, you either check for the correct
output or response in browser, database etc. However this way not all cases are
considered and it is not repeatable and automated. Soon you need something
more reliable and organized.
In PHP there are available many testing tools and frameworks. Testing can be
categorized based on the approach.

Test driven development (aka TDD)

TDD is a software development process in which you repeat very short develop-
ment cycles in which you write code that passes or intentionally fails.

Unit testing

Probably the most used tool and de-facto standard for unit testing in PHP is
the PHPUnit testing framework. It has an awesome manual so do read it and
start using TDD.

Functional testing

By using tools you create automated tests, where application is actually used
instead of just checking certain parts of code.
• Selenium
• Mink
• Codeception

Behavior driven development (aka BDD)

Behavior driven development is a software development process that evolved


from TDD. It makes unit tests more natural by making English sentences that
express certain behavior. Read more about PHP focused BDD in the dedicated
FAQ.

151
Testing spaghetti code

What is spaghetti code?


Spaghetti code is a term for complex unstructured code, which also has lots
of goto statements, exceptions, threads and other unstructured branching con-
structs.
What is Macaroni code?
Languages all mixed up like mac and cheese. For example, SQL and PHP
together.

Why testing code if the application works ok and is in pro-


duction?

• Code can be bad and you want to assure it is working ok


• Maybe there is repeating code in different parts of your application
• When you copy/paste code you can break things. We are a human beings
and we all make mistakes. Also bugs might get copied and pasted besides
the code.

See also

• PHPCI - Free and open source continuous integration specifically designed


for PHP.
• Wikipedia

Behavior driven development


Behavior driven development (BDD) is a software development process that
evolved from TDD. It makes tests more natural by making English sentences
that express certain behavior. It is an outside-in way of developing software,
where you make examples of how the software should behave (feedback from
stakeholders being either clients, your users or you) to achieve certain goals.

StoryBDD

There are two types of BDD - StoryBDD and SpecBDD. StoryBDD focuses
on business and features. Here is a quick and simplified example of a login
functionality based on Behat framework. By communicating with stackeholders,
developers create login scenario (or an example in BDD):

152
Feature: Login
I want to have access to certain page only if I provide
correct username and secret password

Scenario: Checking username and password


Given I am on a login page "login"
And I provide username "foo"
And I provide password "bar"
When I run "Login"
Then I should see:
"""
Login is successful.
"""
This ensures that developers understand how stackeholder want this functional-
ity to work, and that stackeholders expect this functionality to be implemented
like developers are planning to implement it.
Instead of writing unit tests like with TDD, the scenario is also your test before
writing the code.

SpecBDD

The second type of BDD is SpecBDD which focuses on technical behavior of


code. Specifications describe how the certain code should behave. Instead of
testing part of your code, you are describing that part of the code.

See also

Articles and tools you should check out:


• Articles:
– BDD article on Wikipeida
– Introducing BDD - Article by Dan North
– What’s in a story, by Dan North
• PHP Tools:
– Codeception
– Behat - Behavior Driven Development Framework for PHP you
should check out.
– Pho
– PHPSpec
– Kahlan

153
How to debug PHP code? What is debugging?
Debugging is a process to find and reduce number of bugs in your code. An
unavoidable but not particularly fun part of building applications. There are
multiple approaches to debugging available for PHP, but before that, you must
set your development environment up in such a way as to be able to see mean-
ingful errors.

Index

• Prerequisites
• Types of errors
• Syntax errors
• Warnings
• Notices
• Fatal errors
• var_dump/print_r
• Xdebug
• phpdbg
• Symfony VarDumper
• Zend Debugger
• FirePHP

Prerequisites

Turn on error reporting and set the appropriately useful error reporting level,
either in your development code, or better yet, in your php.ini file:
<?php
ini_set('display_errors', 'On');
error_reporting(E_ALL | E_STRICT);

Types of errors

Syntax errors

These are caused by a typo in your code. Examples include missing semicolons,
quotation marks, incorrect variable definitions and so on.

Warnings

Warnings will not break the execution of the script like syntax errors. Warnings
are to notify you when you’ve made a mistake somewhere in your code but when

154
the script can still execute.
Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the fu

Notices

Notices will not break the execution of the script (just like with Warnings), but
they are important pieces of information for debugging your application.

Fatal errors

These errors are quite simple to debug, due to the script will cease execution
when a fatal error occurs. Example of fatal errors include undefined functions,
classes and so on.
Fatal error: Call to undefined function bootstrap() in /var/www/project/index.php on line 23

var_dump/print_r

One of the most common and simple techiques for PHP debugging is using
var_dump or print_r functions:
$date = '28. 04. 2015';
$start = DateTime::createFromFormat('d. m. Y', $date);
die(var_dump($start));
That way you can quickly end execution and check the variable when you want
to know more.

Xdebug

Xdebug - A Swiss-Army knife of PHP, Xdebug is a debugger and profiler that


can be used for more advanced debugging than simply using the var_dump or
print_r functions. It is one of the most commonly used PHP debuggers. Nu-
merous IDEs also utilize it to provide you with a PHP debugging environment.

phdbg

Phpdbg is integrated in PHP since PHP 5.6.0. It is implemented and distributed


as an SAPI module (just like the CLI interface).

155
Symfony VarDumper

You can debug better by using the dump() function of Symfony VarDumper
component than is otherwise possible with using var_dump or print_r.
<?php

require __DIR__.'/vendor/autoload.php';
// create a variable, which could be anything!
$someVar = '...';

dump($someVar);

Zend Debugger

The Zend Debugger is a PHP extension that should be installed on your Web
server in order to perform optimal remote debugging and profiling using Zend
Studio.

FirePHP

FirePHP is a debugger that enables you to log to your Firebug Console using a
simple PHP method call.
<?php

FB::log('Log message');
FB::info('Info message');
FB::warn('Warn message');
FB::error('Error message');

How to write standardized PHP code?


For PHP, there are many standards and coding style recommendations that you
should look into when writing code. It simplifies collaboration on code and
makes it more readable once you get used to a particular style.
One of the most adopted standards recommendations in PHP is PHP FIG, which
recommends coding style via two of its PSRs (PHP Standard Recommendation):
• PSR-1 - Basic Coding Standard
• PSR-2 - Coding Style Guide
Many open source projects also extend the above PSRs with their own coding
style guides, for example:

156
• Symfony
Many advanced PHP IDEs and editors also offer code refactoring via plugins
and extensions. With predefined common coding styles such as PSR-1 and PSR-
2, with refactoring code, automatic code generation, autocomplete and similar
things, consistently writing standardized PHP code can be done with ease.
The more you write code, the more you will understand the importance in using
common style guides. Especially when working with source code control (eg,
Git, coworkers), or just to be consistent in general.

See also

• Core PHP language specification


• PHP_CodeSniffer - Tokenizes PHP, JavaScript and CSS files, and detects
violations of a defined set of coding standards.
• PHP Coding Standards Fixer - A tool that fixes coding standards in your
code.
• PHP-FIG: Extended Coding Style Guide proposal

Where to Get Open Source PHP libraries, scripts


and packages?
There are many places for you to find open source PHP libraries that you can use
in your code. The most libraries from GitHub and BitBucket can be found on
http://packagist.org. For using packagist get to know also Composer, command
line script for managing them in your project.

See also

Other useful resources to check out:


• Awesome PHP - Curated list of PHP ecosystem, present also on libhunt.
• Hoa - set of PHP libraries
• PHP Classes - PHP classes and packages
• PHP Package Checklist - A quality checklist for open-source PHP pack-
ages.
• Producer - Validates and releases your PHP library package.
• The PHP League - group that provides good PHP packages

157
What is Composer?
To not reinvent the wheel you can reuse code in different projects with plugins,
packages, frameworks and similar libraries. Developing and managing release
versions of dependencies in projects on your own can quickly become cumber-
some.
Composer is de-facto standard command line tool for managing dependencies
in PHP.
Packages can be located and developed separately in any public open source
or private proprietary location. Main repository for open source packages is
Packagist.org.

Installation

Download and install composer.phar Phar (PHP Archive) file according to the
documentation. Recommended is to install it globally so you can call composer
from any folder:
$ composer command [options] [arguments]

Usage

Let’s check some basic Composer usage.

Files and folders in PHP project

Composer will add and use the following files in your project:
• composer.json - Metadata file with information about dependant pack-
ages versions autoloading your PHP classes and more.
• composer.lock - After adding dependencies Composer creates this meta-
data file with locked dependency versions for project. If you’re working
on package, don’t include it in the code repository. If you’re working on
application, add it to code repository.
• vendor/ - Automatically managed folder with installed libraries. Don’t
include it in the code repository.
• vendor/autoload.php - Automatically managed PHP classes autoload
mapping file.

158
composer.json

When starting a new project you can use the interactive init command to
create composer.json file:
$ composer init
composer.json is located in the root folder of your project:
{
"name": "vendor/project-name",
"description": "Demo application",
"type": "project",
"require": {
"php": ">=5.6.0",
"nesbot/carbon": "~1.14"
},
"require-dev": {
"phpunit/phpunit": "5.2.*"
},
"license": "MIT",
"authors": [
{
"name": "John Doe",
"email": "john.doe@domain.tld"
}
],
"minimum-stability": "dev"
}

Managing dependencies

To add a new dependency to your project without editing composer.json use


the require command in project folder. As an example, below command adds
Swift Mailer - library for sending emails:
$ composer require swiftmailer/swiftmailer
For updating project dependencies, use update command:
$ composer update
To install project from scratch when you start working on a project:
$ composer install

159
Tips

To improve performance in production optimize the autoloader:


$ composer dump-autoload --optimize
To test if update or install command will have issues use the --dry-run
option. No changes will be made to the project dependencies.
$ composer update --dry-run --profile --verbose

See also

Make sure to read the official documentation to learn Composer in details. Other
useful links to check:
• Climb - Tool that finds newer versions of project dependencies.
• Composer as a service - Give your composer.json, get the corresponding
vendor.zip, fast.
• Melody - One-file Composer scripts.

What is CMS and which one should I use?


CMS (content management system) is an application and unlike a framework it
provides you higher level developed architecture for working with content - pub-
lishing, editing, organizing and deleting. Simple difference between framework
and CMS is that CMS is built with framework.
There are many open source CMSes built with PHP, that might be worth picking
for your project since they speed up the project delivery and they have large
communities behind them which can help you a lot.
Which CMS is right for your project, is quite honestly impossible to answer in
general. You must know the benefits and limitations of them before creating a
project.

Open source CMSes

Some of the recommended open source CMSes built with PHP:


• ATutor
• b2evolution
• Backdrop CMS
• Bolt
• CMS Made Simple
• CMSimple

160
• Composr CMS
• concrete5
• Contao
• Directus
• DokuWiki
• Dotclear
• Drupal
• Exponent CMS
• eZ Platform / eZ Publish
• Geeklog
• GetSimple CMS
• Habari
• ImpressCMS
• ImpressPages
• Jamroom
• Jarves
• Joomla!
• Kajona
• Known
• Magento
• MediaWiki
• Midgard CMS
• MODX
• Moodle
• Novius OS
• Nucleus CMS
• OctoberCMS
• papaya CMS
• pH7CMS
• Phire CMS
• PHP-Nuke
• phpWiki
• pimcore
• PivotX
• Pixie (CMS)
• Pluck
• PmWiki
• Prestashop
• Serendipity
• SilverStripe
• SMW+
• SPIP
• Textpattern
• Tiki Wiki CMS Groupware
• TYPO3
• Wolf CMS

161
• WordPress
• Xaraya
• XOOPS

Content Management Framework

CMS is usually a complete out of the box solution. Content management frame-
work (CMF) on the other hand is a system, which uses reusable components
and is a level between a framework and a CMS. It enables you to make your
CMS more customized. Many CMSes listed above have characteristics of CMF
as well however the following examples are some more notable content manage-
ment frameworks by the definition:
• Symfony CMF

See also

• Wikipedia: List of content management systems

Which eCommerce application should I use or


which framework to use for building eCommerce
application?
Same question as with frameworks, CMSes and similar open source solutions
comes as well with which eCommerce PHP application to use.
There are quite a lot of existing open source very good solutions for eCommerce
purposes currently available in PHP. Choosing the right one for the project or
a right PHP framework for eCommerce depends on your knowledge and project
specifics.
Some of popular eCommerce solutions:
• Magento
• OpenCart
• Prestashop
• Sylius
• Virtuemart
• ZenCart

162
How to work with Excel in PHP?
PHPExcel library can be used to read, create and write spreadsheets. It can be
installed via Composer. Use the provided Composer instructions below.
Simple and recommended way to install PHP library using Composer is with
composer require command.
$ composer require phpoffice/phpexcel
The alternative way is to manually add the code below in composer.json file:
"require": {
...
"phpoffice/phpexcel": "1.8.1"
...
}
After adding above in composer.json, install the newly added library and up-
date all the dependency versions for the current project with composer update:
$ composer update
Once new project’s dependency is installed we can start working with PHPExcel.

Example

After composer update command is complete, create a new file named


create_excel.php at the project root. composer.json and newly created file
should be on the same level in the project root. In create_excel.php file
paste the below sample code snippet. After that browse the php page in the
browser. This will create a new excel sheet create_excel.xlsx in the same
folder where create_excel.php is.
<?php
/**
* Always refer to the package documentation for the latest example
* @see http://phpexcel.codeplex.com/wikipage?title=Examples
*/
require __DIR__.'/vendor/autoload.php';

echo date('H:i:s') . " Create new PHPExcel object\n";


$objPHPExcel = new PHPExcel();

// Set properties
echo date('H:i:s') . " Set properties\n";
$objPHPExcel->getProperties()->setCreator("Maarten Balliauw");
$objPHPExcel->getProperties()->setLastModifiedBy("Maarten Balliauw");

163
$objPHPExcel->getProperties()->setTitle("Office 2007 XLSX Test Document");
$objPHPExcel->getProperties()->setSubject("Office 2007 XLSX Test Document");
$objPHPExcel->getProperties()->setDescription("Test document for Office 2007 XLSX, generated

// Add some data


echo date('H:i:s') . " Add some data\n";
$objPHPExcel->setActiveSheetIndex(0);
$objPHPExcel->getActiveSheet()->SetCellValue('A1', 'Hello');
$objPHPExcel->getActiveSheet()->SetCellValue('B2', 'world!');
$objPHPExcel->getActiveSheet()->SetCellValue('C1', 'Hello');
$objPHPExcel->getActiveSheet()->SetCellValue('D2', 'world!');

// Rename sheet
echo date('H:i:s') . " Rename sheet\n";
$objPHPExcel->getActiveSheet()->setTitle('Simple');

// Save Excel 2007 file


echo date('H:i:s') . " Write to Excel2007 format\n";
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$objWriter->save(str_replace('.php', '.xlsx', __FILE__));

// Echo done
echo date('H:i:s') . " Done writing file.\r\n";
Refer to the latest version of PHPExcel on Github to learn more.

See also

Learn more:
• Read and Write Microsoft Excel Files in PHP: Part 1, and Part 2.

Are there any image manipulation libraries in


PHP? Which ones are good?
Resources and image libraries:
• PHP’s GD manual - PHP manual about image processing, generation and
GD
• Imagine - PHP 5.3+ Object Oriented image manipulation library
• Image - PHP Image library

164
How to add pagination?

See also

Some useful libraries and resources to check out:


• PagerFanta - Useful pagination library for PHP.
• KnpPaginatorBundle - Pagination bundle for Symfony2

What is payment gateway? How to integrate and


use payment gateways in PHP?
Payment gateways are e-commerce application service provider services that au-
thorize credit card payments for e-businesses, online retailers, bricks and clicks,
or traditional brick and mortar.
Payment gateways link your website to your processing network and merchant
account. In other words they facilitates the transfer of information between a
website and the Front End Processor or acquiring bank.
Resources and PHP libraries to check out:
• PHPLeague Omnipay - a framework agnostic, multi-gateway payment pro-
cessing library for PHP 5.3+
• TrustPay - an international payment gateway
• PayPal documentation - a documentation for processing payments through
PayPal

How to work with PDF files in PHP?


In your application you will often need to create PDF files. For creating PDF
files usage of PHP’s PDF functions is advised.
Often this is not enough and you need extra functionalities on top of PHP PDF
functions. PHP libraries and resources to check out:
• FPDF - Open Source PHP class for generating PDF documents
• FPDI - Collection of PHP classes to read pages from PDF
• PDF libraries on packagist - PDF libraries on packagist
• PHPPdf - Pdf and graphic files generator library written in php
• TCPDF - Open Source PHP Class for generating PDF documents
• Dompdf - Open Source HTML layout and rendering engine written in
PHP

165
PHP packages
Here is a collection of some useful libraries, packages and scripts you will find
useful when developing with PHP.

Administration

• EasyAdminBundle - Administration panel for Symfony based projects.


• Laravel-Administrator - Administration interface package for Laravel
based projects.

Images

• Imagine - Image manipulation library.


• ImageWorkshop - ImageWorkshop is a PHP5.3+ library that helps you to
manage images based on GD library.
• Zebra Image - lightweight, image manipulation PHP library.

Pagination

• PagerFanta - Pagination library for PHP.

Payment gateways

• Omnipay - Multi-gateway payment processing library.


• Stripe - PHP bindings fro Stripe
• Paypal PHP SDK - PHP SDK for PayPal RESTful APIs
• Stripe - PHP bindings fro Stripe

Excel

• PHPExcel

Authentication

• HybridAuth - OAuth login library for various social network such as Face-
book, Twitter, Google+…
• oauth2-server-php - OAuth 2 login Library to make your own OAuth 2
Appliction
• auth0-PHP - PHP SDK for auth0 service

166
Bitcoin/Altcoin

• Bitcoin data explorer - Altcoin/Bitcoin data Explorer. This package can


get transaction information with Bitcoin protocol.

Serialization

• Flatbuffers - Serialization library for games and other memory constrained


apps.

Encryption

• Time lock encryption - This class can encrypt data using key generated
for a time period.
• Fernet - Fernet takes a user-provided message (an arbitrary sequence of
bytes), a key (256 bits), and the current time, and produces a token, which
contains the message in a form that can’t be read or altered without the
key

MySQLi

• MysqliDb - Simple MySQLi wrapper and object mapper with prepared


statements
• simple-mysqli - PHP class to access MySQL database wrapper using
MySQLi.

PDO

• salebab/database - PHP/MySQL database wrapper, extends PDO and


PDOStatement.
• nikic/DB - PDO wrapper class

ORM

• Doctrine2 - Doctrine 2 Object Relational Mapper (ORM) (Symfony


projects)
• Propel2 - Propel2 is an open-source high-performance Object-Relational
Mapping (ORM) for modern PHP

167
PDF

• FPDF - Easy to use PDF generation library


• TCPDF - Same as FPDF but a little bit more advanced

Sanitization

• HTML Purifier - A standards-compliant HTML sanitization library.

MarkDown

• PHP Markdown - PHP Markdown parser.

Geometry

• geoPHP - Advanced geometry operations in PHP.


• PHP-GPX-Ingest - Simple class to ingest a basic GPX file and extract
data/stats from it.
• phpGPX - PHP library for manipulation with GPX files (read, write, stats
calculation).

What is API?
API, which stands for “Application programming interface”, is a set of routines,
protocols, and tools for building software applications.

Useful tools

• Apiary - API Design Stack built for developers.


• Swagger - Swagger is a simple yet powerful representation of your RESTful
API.

Documenting

• ApiBlueprint - A powerful, high-level API description language for web


APIs.

168
See also

Useful frameworks, libraries, and reading material for building APIs.


• API Platform - API-first web framework on top of Symfony with JSON-
LD, Schema.org and Hydra support.
• Apigility - An API builder built with Zend Framework 2.
• DC4D - Building APIs developers will love and use, free video tutorials
about APIs. Registration required though.
• HAL - A HAL (Hypertext Application Language) builder library.
• Insomnia - Free REST API client.
• Negotiation - A content negotiation library.
• Undisturbed REST: A Guide to Designing the Perfect API
• Silex: A PHP micro-framework standing on the shoulder of giants
• Lumen: The stunningly fast micro-framework by Laravel.
• Slim: Slim is a PHP micro framework that helps you quickly write simple
yet powerful web applications and APIs.
• API Security Checklist - Checklist of the most important security coun-
termeasures when designing, testing, and releasing your API.

What is REST?
REST stands for “Representational State Transfer.” It was claimed by Roy
Fielding in his doctor dissertation in 2000.

What is the difference between REST and RESTful?

The term RESTful refers to web services implementing such a REST architec-
ture.

See also

PHP libraries and resources to checkout.


• Bullet PHP - A micro framework for building REST APIs.
• Hateoas - PHP library to support implementing representations for HA-
TEOAS REST web services.
• RESTful APIs, the big lie - Technical critique which introduces some
issues of REST and how JSON-Pure APIs could do better, with a follow-
up article.
• Restler - A lightweight framework to expose PHP methods as RESTful
web APIs.

169
• Fusio - Fusio is an open source API management platform which helps to
build and manage REST APIs.
• Slim - Slim is a PHP micro framework that helps you quickly write simple
yet powerful web applications and APIs.
• Api Platform - The ultimate PHP framework to build modern web APIs.

What is SOAP and how to use it in PHP?


SOAP (Simple Object Access protocol) is a protocol specification for web ser-
vices that exchange information in the form of an XML Information Set.

See also

Libraries and reading material to check out.


• NuSOAP - SOAP Toolkit for PHP.
• PHP SOAP extension manual
• Zend\Soap - Standalone Zend SOAP component.

Which editor and IDE to choose for writing PHP


code?
Most of your time choosing a right tool for the job is important. So is picking
the editor or IDE (integrated development environment) in which you will write,
edit, debug and test your code and spend a lot of your time.

IDE vs editor

There are many open-source and proprietary text editors and IDEs available
on the market today. Difference between editor and IDE is in functionalites
and extensions that IDE holds over a plain text editor. Many editors have
capabilities to be extended to a full IDE as well but experience in dedicated
IDEs are better for complex and bigger projects. IDE has more features than
editor but also takes more resources on your computer.

How to choose IDE/editor?

Following and looking up to other good developers and/or teammates in your


organization what they use for writing code is a good approach for you to choose
an IDE/editor.

170
Listing tools always leads to flamewars between users using them convincing
each other to “buy” theirs. We’re not trying to start a flamewar here but to
only show some of the good tools you should check out for your development
and pick the right one for you.
Many times you will need both - editor and IDE. IDE for bigger project itself
and editor for quick edits here and there. If you will be working in command
line some text-based editors such as Vim or Emacs will be a must to use.

IDEs

Alphabetical list of good IDEs for PHP:


• Aptana
• CodeLobster
• Eclipse PDT
• Komodo IDE
• Netbeans
• PHPDesigner
• PHPStorm
• Zend Studio

Editors

Alphabetical list of good text editors for PHP:


• Atom
• Bluefish
• Brackets
• Coda
• ConTEXT
• Emacs
• Geany - text editor using GTK2 toolkit
• Kate
• Komodo Edit
• Light Table
• Notepad++
• PSPad
• RJ TextEd
• Sublime
• TextPad
• Vim
• Visual Studio Code

171
Client side development

Most IDEs listed above also take care of client side development part i.e. HTML,
CSS, JavaScript and web publishing but sometimes some dedicated tools for that
are irreplaceable:
• Dreamweaver - proprietary tool
• KompoZer - free web authoring system that combines web file management
and easy-to-use WYSIWYG web page editing.
• WebStorm - JavaScript IDE also useful for complex complex client-side
development and also backend Node.js development.

Atom editor for PHP developers

Figure 16: “Atom Editor”

Atom is an advanced open source text editor for developers. This article will
explain some useful packages and tricks how to make the most out of it when
developing with PHP.

IDE or editor?

First, a bit of an introduction and comparison between IDE (integrated develop-


ment environment) and editor. IDE provides more functionality out-of-the-box
compared to an editor. So why would you want to use an editor in the first
place?
Editor usually requires less computer resources and can work faster compared
to an IDE. Also the learning curve and time to get used to an editor is less steep.
And on top of that editor can still be customized with additional packages to
behave a lot like an IDE.

172
One of the recommended ways to develop applications is for example, to use
an IDE for developing the project at large and an editor for quick edits across
different projects or folders. However you can successfully develop PHP projects
also without an IDE. Explore and try different tools to see what suits your
development workflow. Make sure that the tools you use, make you productive.

Atom installation

Installation of Atom is as simple as it gets and works on all widely used operat-
ing systems (Linux, Windows and macOS). Visit the Atom homepage and the
releases on GitHub to download the installation for your system.

Themes

By default, Atom comes with multiple nice themes you can use out of the box.
Additional themes can be obtained from Atom themes repository.

Figure 17: “Atom Themes”

Configuration

Nice thing about Atom is that it can be customized to do almost anything.


Configurations can be set via the menu Edit > Preferences.

173
Figure 18: “Atom Preferences”

The configuration files are saved in your home directory ~/.atom, so you can
backup them to your dotfiles and have a portable configured development envi-
ronment for multiple development machines.
Some of the portable files in that folder are config.cson, keymap.cson,
snippets.cson, and styles.less. The installed packages can also be
exported to a custom list file via command line:
apm list --installed --bare > packages.list
When you will need to reinstall Atom, the saved packages list can be used to
quickly install all your favorite packages:
apm install --packages-file packages.list

Code style

By default, Atom already supports syntax highlighting and snippets for a lot
of languages. For PHP it uses the language-php package. To set your pre-
ferred coding style such as spaces/tabs, line ending, and similar go to Edit >
Preferences > Packages and type language-php and set some default behav-
iors you use. In the following section we’ll check some packages that can improve
and extend managing code style in your PHP project.

Packages

Atom packages extend core editor functionality. They can be obtained from the
Atom packages repository.

174
Packages can be installed via the GUI Edit > Preferences > Install or with
the command line Atom package manager apm:
apm install package-name
By default, Atom provides basic editing capabilities and everything you need
to write PHP code. There are many packages to extend and make writing
PHP code more efficient and provide a much better development experience. If
you are used to some advanced IDE functionality already, you’re familiar with
things such as autocompletion, code inspection, generating code snippets and
more. There are a lot of Atom packages for PHP development, however you
might want to take a look at some of the following highlighted packages for
having PHP development more efficient.

Atom beautify

Figure 19: Atom Beautify

Did you get a code that is not suited for your coding style? The atom-beautify
package is a must check for having a consistent code style and to beautify the
code on the fly. It cleans the code for multiple languages according to the
predefined code style settings. To successfully beautify PHP code, you must
also separately install either the php-cs-fixer or the PHP Code Sniffer.

175
Editorconfig

To have a consistent code style across different editors for multiple people, you
might want to take a look at Editorconfig initiative. The editorconfig package
adds support for .editorconfig file to Atom.

PHP Integrator

PHP Integrator is a collection of multiple Atom packages to provide a better


PHP development experience. To install and successfully use PHP Integrator
packages you will first need to install some prerequisites:
• PHP
• php-sqlite extension
• php-mbstring
• openssl
• project-manager package
• php-integrator-base package
After base PHP Integrator installation save your PHP project in Project Man-
ager (Packages > Project Manager > Save Project) and index it with PHP
integrator (Packages > PHP Integrator > Set Up Current Project) which
will index project files for further usage.
PHP Integrator and Linter inspect and validate your PHP code for errors, check
PHP DocBlocks and more.

Figure 20: Atom PHP Integrator Linter

PHP Integrator shows tooltips (e.g. for methods and classes) in your PHP source
code.
PHP Integrator includes call tips with parameter information in your PHP
source code for functions and methods.
With PHP Integrator installed and project prepared, you can check the following
additional packages from PHP Integrator collection:
• PHP Integrator Autocomplete Plus

176
Figure 21: Atom PHP Integrator tooltips

Figure 22: Atom PHP Integrator call tips

Figure 23: Atom PHP Integrator Autocomplete

177
The php-integrator-autocomplete-plus package provides autocompletion for
your PHP source code. By indexing project files, autocompletion works also
for classes from project and Composer’s vendor folder. Class is automatically
added to the list of used classes on top of a current PHP file.
• PHP Integrator Navigation

Figure 24: Atom PHP Integrator Navigation

The php-integrator-navigation package provides code navigation and go to func-


tionality for your PHP source code. For example, clicking a class opens the
source code file. Opening can be done by adjusting the settings (Alt + left
mouse click, Shift+ left mouse click or similar).
• PHP Integrator Refactoring
The php-integrator-refactoring package provides refactoring capabilities for your
PHP source code. It generates getters and setters for PHP classes and similar.
Keybinding: Alt + Enter.
• PHP Integrator Annotations
The php-integrator-annotations package shows which methods override their
interface implementations.

PHP Debug

The php-debug package is PHP code debugging package using the Xdebug ex-
tension.

178
Figure 25: Atom PHP Integrator Refactoring

Figure 26: Atom PHP Integrator Annotations

179
PHP Server

The php-server package runs PHP development server on your localhost.

Above we’ve gone through some of the useful packages for PHP. To improve
development experience and add additional functionality you might want to
check these awesome packages.

Minimap

Figure 27: Atom Minimap

The minimap package adds file preview on the sidebar. Once you get used to
it, it is a must have package in your collection. It is useful for easier overview
of the source code and quicker navigation over the file.

Highlight Selected

The highlight-selected package highlights the current word selected when double
clicking. If you’re using the minimap package there is also minimap-highlight-
selected.

Atom Minify

The atom-minify package minifies JavaScript and CSS files. It is useful when
you come across a need to manually quickly minify a required file on the fly.

180
Todo Show

The todo-show finds all TODO, FIXME, CHANGED and similar comments in your
project and shows them in a nice overview list.

Color Picker and Pigments

The color-picker package opens color picker for color codes such as HEX by using
right click or pressing CMD-SHIFT-C/CTRL-ALT-C. Pigments displays colors for
color codes in the editor itself.

Ctrl-dir-scroll

The ctrl-dir-scroll package is convenient for users who are used to shortcuts from
some other IDEs and editors. By default, Atom uses Ctrl and up/down keys
to move the line up and down. This package adds scrolling up and down with
keyboard - CTRL and up/down keys.

Project Manager

The project-manager package helps you manage multiple projects.

Emmet

Emmet adds support for Emmet.

Docblockr

Docblockr is a helper package for writing documentation.

File Icons

The file-icons package adds icons in tree view for recognized file types.

Framework specific packages

PHP frameworks are supported by multiple packages which provide additional


functionality such as code snippets.
• CodeIgniter
• Drupal

181
• Laravel
• Symfony
• WordPress

Docker

Developing with different PHP installations, extensions and dependencies soon


requires virtualization and/or containerization such as Docker. Docker can be
optionally integrated in Atom with additional plugins:
• language-docker
Adds Dockerfile syntax highlighting.
• docker
Integrates Docker with Atom editor.

Shortcuts and useful features

Keyboard shortcuts can make you more productive. These are some of the
keyboard shortcuts you might find useful. On Linux and Windows use the Ctrl
key, and on macOS the Cmd.
• Comments: Ctrl + /
Comments/uncomments selected code.
• Find and open a file: Ctrl + p
• Command Palette: Shift + Ctrl + p
Command palette simplifies access to find and run available commands instead
of going through the menu manually.
• Multiple cursors:
With Ctrl and left mouse click you can add more cursors to the editor which
behave the same as a single cursor. This is useful for changing multiple same
values on different parts of the file.

Caveats and final thoughts

Performance

Having installed and enabled a lot of packages might also slightly slow down the
performance. When opening very large files (few MB), the editor performance
can decrease and the editor becomes unresponsive. Currently Atom supports
files up to few MB (~10MB), and works a bit better on Linux and macOS

182
Figure 28: Atom Command Pallete

Figure 29: Atom Multiple Cursors

183
systems. This has been already noted on Atom issue tracker, so it might be
fixed in the future.
How to deal with the issue of very large files (for example, log files)?
Many GUI editors and IDEs have same issues when opening and working on
large files. People usually solve this with the command line tools like grep, cat,
head, tail, and sed. For compressed files there are also zless, zmore, zcat,
and zgrep.

Learning curve

At first, Atom might seem a bit overwhelming, specially to fine tune it for your
needs. So, as with every tool, take some extra time and read the documentation
to get to know it in more details.
Multiple community packages can have the same keybindings and in this case
need to be reconfigured manually.
Which packages to install and which not is your choice and preference. For
PHP development in particular, many tasks can be done by using native tools
in the command line instead of using editor plugins. For example, unit testing,
running Docker containers, deployment, running up local development server
and similar.
Atom truly is a magnificent editor worth taking a look. It has a huge community
behind and it is open sourced.

See also

Some additional useful resources:


• Atom Flight Manual - Official book about Atom.
• Atom in Orbit - Atom in the browser.
• Awesome Atom - A curated list of delightful Atom packages and resources.
• Nuclide - A package built on top of Atom for React Native, Hack and
Flow projects.

What is GIT?
Git is one of the most popular free and open source distributed version control
system designed to handle everything from small to very large projects with
speed and efficiency.
Working on code requires a version control system and Git is highly recom-
mended for versioning PHP code, whether you work on code alone or in a team.

184
It provides patches, history, rollbacks, code versioning and more for your PHP
project as well.

Installation

Git is available for download for multiple operating systems.

Linux

To install Git on Linux operating systems best is to use your package manager,
such as apt-get, yum, dnf, pacman or pip.
For example, Debian based distributions using apt-get:
sudo apt-get install git-all
Or for Fedora based distributions:
sudo yum install git-all

macOS

macOS Sierra and OS X (until El Captain) don’t include an up to date Git. Git
is bundled with macOS, here is how to upgrade it:
If you do not have brew, install it:
• Install Xcode from the App Store and run xcode-select --install after
the successful installation.
• Install brew
Now install Git, brew will delegate a soft link into a higher path’ed directory:
brew install git
You could install Git in other ways (there is an official .dmg-image with an
installer). But this will force you to always handle those updates by yourself.
This will update everything:
brew update && brew upgrade `brew outdated`

Windows

Beside the Windows installation on the main download page there is also Git for
Windows, providing dedicated instructions for installation and adds neat shell
integration.

185
Commit messages

Commit message is the log information about the change made to the code
in the repository. Generally these must be informative and include all the
information needed about the change. For small changes they can be short, for
bigger changes they should be longer.
Some useful rules of a thumb for commit messages:
• Make the title of the commit message 50 characters or less;
• Put more information in the body part of the message (body starts after
two new lines after the title);
• Use imperative for the message title - Add new function not New
function added;
• Wrap body text to 72 characters
A Note About Git Commit Messages, by Tim Pope suggests a model you should
use for writing useful Git commit messages:
Capitalized, short (50 chars or less) summary

More detailed explanatory text, if necessary. Wrap it to about 72


characters or so. In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body. The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.

Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug." This convention matches up with commit messages generated
by commands like git merge and git revert.

Further paragraphs come after blank lines.

- Bullet points are okay, too

- Typically a hyphen or asterisk is used for the bullet, followed by a


single space, with blank lines in between, but conventions vary here

- Use a hanging indent

Open source

When creating Git repository in public Git hosting services such as GitHub,
best practice is to add also some of the additional files to the repository which
describe the repository and your code with more details:

186
• README.md - introduction file about the project; (art-of-readme).
• CHANGELOG.md - Change log of the tagged versions using semantic versions.
Dedicated site Keep a CHANGELOG describes, why is useful having a
separate change log for your repository and how to format it.
• CONTRIBUTING.md - Open source projects usually add the file describing
how to get involved and send your patches to the repository.
• LICENSE - License of the repository.
• CONDUCT.md - Some open source projects include also their code of conduct
to let the users know what is appropriate and what not. Specially in larger
and diverse communities having such information adds extra value to the
project. Having a welcoming and inclusive environment is important for
people contributing to your project.

See also

Useful resources to read more about Git:


• Git homepage - homepage of Git version control system with documenta-
tion;
• Pro Git book - detailed and useful book dedicated to Git usage with usage
examples;
• Interactive Git Tutorial from GitHub
• Git Lint - PHP library for linting git commit message style
• Nomad PHP: Commit Messages I have seen - lightning talk

Which are recommended libraries and resources


to use with PHP?
To successfully develop applications here are some recommended development
libraries and resources you will like and can enrich experience.
• AJAX:
– Backbone.js - Structure to web applications that involve JavaScript
and data.
– jQuery - Useful JavaScript library for easier AJAX, HTML document
traversal and manipulation, event handling, animation etc.
• File upload:
– Dropzone.js - Drag’n’drop file uploads.
• User interface:
– Semantic UI - Framework that helps you create beautiful, responsive
layouts using human-friendly HTML.

187
Nopaste list and services to share and run code
online

What is a nopaste?

The term nopaste is a term used on the internet meaning to paste source code to
a separate, dedicated site, and to then link to that pasted source code in forum
discussions, chats, and so forth, instead of pasting that source code directly.
Many discussion forums and chat rooms don’t have an option of treating code
in messages properly. Nopaste sites usually also offer syntax highlighting, a
history of code changes, commenting on lines of code and similar.

List of nopaste services

Nopaste services for different code purposes and languages:


• codepad - Multiple languages
• CodePen - HTML, CSS and JavaScript
• Codejaw - Multiple languages
• GitHub Gist - Multiple languages
• JSFiddle - JavaScript
• Nopaste.me - Multiple languages
• Pastebin - Multiple languages
• Pastee.ee - Multiple languages
• PHPTester - PHP
• Regex 101 - Regular expressions
• SQL Fiddle - SQL
• Pasted.co - Multiple languages
• hastebin - Simple, Notepad-style editor
• PasteFS - Simple text editor
• Ubuntu pastebin - Multiple languages

Run and execute code online

For sharing, reviewing, and quick testing code snippets; the following services
also execute your code online:
• PHP Live Regex - Regular expressions for PHP
• Online PHP Functions Sandbox - PHP
• 3v4l - Run PHP code in multiple PHP versions.
• eval.in - Execute code online, multiple languages.
• Runnable - Run multiple languages using advanced stacks.
• WritePHPOnline - Run PHP Code.
• Ideone - Run multiple languages.

188
• PHPFiddle - Run PHP Code with different Libraries.

Online editors

Useful editors, code hosting services and tools for online collaboration:
• Etherpad
• Cloud9
• GitHub
• GitLab
• Bitbucket
• Orionhub
• Collabedit

Screenshot sites

For sharing screenshots


• Snaggy
• Pasteboard

Vagrant tutorial
1. What is Vagrant?
2. Installation
3. Project setup
4. Boxes
5. What is PuPHPet?
6. How to save your changes on a box?
7. Resources
In this tutorial you will learn how to quickly use Vagrant for PHP development.

What is Vagrant?

Vagrant is a wrapper around the virtualization software such as VirtualBox for


configuring and creating virtual development environments. Perfect for PHP
development. You can have a development environment that is identical to
your production environment. So far you’ve probably used setups like Xampp,
Wampserver or similar all-in-one package that contained PHP, MySQL and
Apache on your development machine. That is all fine but with Vagrant you
will become more flexible and you can share your development environment with
your teammates.

189
Installation

Before installing Vagrant, you must install a virtualization software such as


VirtualBox. Installation of Vagrant is very simple and works on all popular
operating systems - Windows, Mac and Linux. Download Vagrant or install it
with package manager for your Linux distribution.

Project setup

All the commands in this tutorial must be typed in your terminal:


$ mkdir vagrant-project
$ cd vagrant-project

Boxes

Boxes in Vagrant are base images of virtual machines.


With command vagrant init you get a Vagrant configuration file called
Vagrantfile with instructions for Vagrant to set up your development
environment and a so called base box.
Next step after creating Vagrantfile is adding a box. In this tutorial we’ll use
Puphpet’s Debian box. Don’t let the name confuse you - it is the latest Debian
box.
$ vagrant box add puphpet/debian75-x64
This downloads the base image you can use in your development environment.
To ssh into your newly added box, use the following commands:
• vagrant up starts your vagrant box. It’s equivalent to hitting the “Power
ON” button on your physical machine.
$ vagrant up
• Once the box is up, it can accept SSH connections. By default SSH will
be passwordless and is configured to key pairs.
$ vagrant ssh

What is PuPHPet?

PuPHPet is a simple GUI to set up virtual machines for Web development.

190
How to save your changes on a box?

When you make some changes on the box you’ve downloaded in previous steps,
you will loose them when you make:
$ vagrant destroy
In order to save the entire box you can make a new box based on the current
running virtual machine. This creates a package named package.box:
$ vagrant package --output package.box
You can than add this package to your base boxes:
$ vagrant box add your_name/distribution package.box
And use it like before:
$ vagrant init your_name/distribution

See also

• Vagrantup - Vagrant’s official homepage


• Vagrant Boxes - list of base boxes for Vagrant
• Vagrant Cloud - hosting and discovery of Vagrant Boxes, as well as other
features like Vagrant Share
• Puphpet homepage - GUI for setting up virtual machines for web devel-
opment

Web assets (images, JavaScript, CSS files)


Assets are front end and static files such as CSS stylesheets, JavaScript files,
images and similar.
There are multiple approaches you can check out when working with these files
in your PHP application.
Handling these files usually includes installation from 3rd party location
(GitHub), and copying the required files to your publicly accessible folder, such
as web, public_html and similar.
After installation you usually also want to minimize JavaScript and CSS files.
For images maybe you need to create favicons for multiple devices from source
logo of the website and similar.
• Assetic
• Composer
• Bower

191
• BowerPHP
• Grunt
• NPM and Gulp
• Robo
• Webpack
Many developers also use approach of developing a project with two separate
repositories - one for back end (PHP application) and one for front end.
The API points in the back end part are connected with the front end. Main-
taining and scaling to application requirements can be much easier.

Content delivery network (CDN)

High traffic and complex sites many times also create a separated CDN for
serving these static files. This can improve the performance since the asset is
downloaded only once from a separate location.
For many open source front end libraries, many times using a publicly available
CDNs is advices since it reduces the required number of requests and traffic for
your application.

See also

• Wikipedia: CDN
• Gulp: Refreshment for Your Frontend Assets
• Sitepoint: A PHP Front End Workflow without Node.js

Performance benchmarks and load testing


Benchmarking your application is important to see how the application performs
under heavier traffic and load.

Apache HTTP server benchmarking tool

Very common benchmarking tool you can use is ab.


ab -c 10 -n 1000 http://localhost/

Authentication

Stage and beta environments can be sometimes closed for public with HTTP
authentication. To pass username and password:

192
ab -c 10 -n 1000 -A username:password http://beta.example.org/

Siege

Siege is an http load testing and benchmarking tool. Its source code is available
on GitHub.
siege -c 10 -r 100 -b -i http://localhost

JMeter

Apache JMeter is a more feature rich load tester.

Gatling

Gatling is a load tester with GUI.

HTTP keep-alive

HTTP keep-alive or HTTP persistent connections greatly improve performance.


In performance testing you can enable them and get better results, however
these vary from one testing software to another. Good practice is to disable
them and get comparable results among the above tests.

What is PHP community? What are PHP user


groups?
One of the main advantages of using PHP is its awesome, large and diverse
community behind it. The community consists of PHP libraries, frameworks,
CMSes and other PHP applications and also great, open minded people that
are connected with each other one way or another.

PHP UG concept

PHP User Group (PUG) is virtual or real in-place community consisting of local
people participating and organizing PHP conferences and meetings. You can
find your local user group at official PHP user groups list which is based on the
PHP.ug. In case there is no local PHP User Group near you, find some friends
interested in PHP and start your own local user group.

193
Figure 30: PHP User Grups

194
Many meetup and conference organizers use also Meetup for organizing and
sharing PHP meetings.

PHP community

• Google+ - Large and active PHP group on Google+


• Linked.in - Discussion group on Linked.in for PHP developers
• Nomad PHP
• PHP Classes - PHP specialists forum
• PHP community on Twitter
• Freenode:
– #php - Active support IRC channel for PHP users
– #phpc - PHP community on IRC
• PHP on Reddit
• PHP tag on Stackoverflow
• PHP UG Wiki
• PHP Women
• Quora - PHP questions and answers on Quora
• Sitepoint - SitePoint forums with PHP discussions and support

Content management systems

Many of the popular PHP Content Management Systems (CMSs) have an active
and supportive community, both online and in the real world.

Drupal

• Drupal Forum - Online help and support from the Drupal community.
• Drupal Groups - A place for groups to organize, plan and work on projects,
both online and in real world user groups (sometimes called meetups).

Joomla

• Joomla Forum - Online help and support from the Joomla community.
• Joomla User Groups - Search for a local Joomla User Group. They regu-
larly host meetups with talks, ‘clinics’ and networking.

WordPress

• WordCamp Central - WordCamps are casual, locally-organized confer-


ences covering everything related to WordPress.

195
• WordPress Forum - Online help and support from the WordPress commu-
nity.

Frameworks

Some of the popular frameworks and their online forums:

Laravel

• Laravel.io - Online help for laravel related issues also shares laravel based
jobs.
• Laracasts- Official Dissusion forum of Laravel.

CakePHP

• CakePHP Forum - Online help and support from the CakePHP.


• CakePHP Community - Official CakePHP community on Google+.

CodeIgniter

• CodeIgniter Forum - Official discussion CodeIgniter forum.


• CodeIgniter IRC - CodeIgniter IRC Channel.

Symfony

• SensioLabs Connect - SensioLabsConnect is an extensive professional net-


work for Symfony developers.

See also

Additional interesting and amazing resources about PHP community:


• 7 PHP

What are PHP conferences and where can I at-


tend one?
PHP conferences are PHP specific events, at which established, well known PHP
speakers present their topics and users meet and discuss PHP related topics and
have fun. They occur all over the world in many countries.

196
PHP.net always updates and announces PHP conferences from all over the world.
You can check the list of current conferences happening in the PHP’s conference
section.
There are some established conferences located in very comfy and easy to visit
locations.

Highlighted PHP conferences

• Bulgaria
• PHP Bulgaria
• http://www.bgphp.org/
• Croatia
• Web Summer Camp 2017
• http://2017.websummercamp.com/
• Germany
• International PHP Conference
• https://phpconference.com/en/
• Italy
• PHP Day
• http://2017.phpday.it/
• Netherlands
• Dutch PHP
• https://www.phpconference.nl/
• LaraCon EU
• https://laracon.eu/2017/
• Romania
• SymfonyCon Romania
• http://live.symfony.com/
• Serbia
• PHPSerbia
• http://www.conf2017.phpsrbija.rs/
• USA

197
• LaraCon US
• http://laracon.us/
• Symfony Live San Francisco
• http://live.symfony.com/
• php[cruise]! - Baltimore
• https://cruise.phparch.com/
• PHPtek
• https://tek.phparch.com/
• Lone Star
• http://lonestarphp.com/
There are a lot more.

What is ElePHPant and why PHP uses elephants


in some logotypes?
ElePHPant is that adorable PHP mascot with an elephant in its design.
The ElePHPant logo was originally introduced and created in 1998 for the PHP
community by Vincent Pontier - spiritual father of thousands of ElePHPants
around the world. In 1998, there were mostly CGI scripts used for dynamic web-
sites. Vincent’s friend, François Buffière, introduced him to the PHP language.
Vincent came up with the ElePHPant by drawing PHP letters on a paper and
playing with them a little. He noticed they were in shape of an elephant.

Figure 31: Blue ElePHPant

198
At that time in France only few sites were talking about PHP. One was Jean-
Pierre Dezelus’ page and he was also a collector of elephants. He asked Vincent
to make an elephant logo for PHP with same style as the original PHP logo - a
blue oval with black outline gradient.
Then the original ElePHPant logo came to birth:

Figure 32: Original ElePHPant logo

The plush animal toy - ElePHPant came to birth 10 years later.


ElePHPants are present at many PHP conferences and computers for inspiration
and fun.

Other reincarnations of ElePHPant

Many PHP projects have also made custom variations of the ElePHPant with
their logo on it.

PHP Women’s purple ElePHPant:

PHP Women successfully made a Kickstarter project in which they created


purple officially dimensioned ElePHPant.

199
Figure 33: PHP Women ElePHPant

200
PHP Architect’s orange ElePHPant - Archie:

PHP Architect followed and they made an orange ElePHPant on Kickstarter.

Figure 34: PHP Architect’s Orange ElePHPant

Laravel’s ElePHPant

A red Laravel ElePHPant has been made by using Kickstarter.

AmsterdamPHP ElePHPant

AmsterdamPHP User Group Kickstarer campaign started with black ElePH-


Pant

201
Figure 35: Laravel ElePHPant

202
Figure 36: AmsterdamPHP ElePHPant

203
Golden Elephpant

For the special occasion of 20 years of PHP, one of a kind golden ElePHPant
was created.

Figure 37: Golden ElePHPant for 20 years of PHP

PHP 7 ElePHPant

PHP 7 Elephpant has been created for PHP 7 and as a gift for visitors at
ZendCon 2015.

Symfony ElePHPant

For the 10 years of Symfony project black Symfony ElePHPant has been made.

TrueNorth PHP Woolly Mammoth

The great ancestor of the PHP Elephpant, the PHP Woolly Mammoth immor-
talized by the True North PHP conference.

PHP Classes ElePHPant

PHP Classes Elephpant given to the Innovation Award Winners each year.

204
Figure 38: ZendCon PHP7 ElePHPant

There are many more to be listed here. Explore the PHP universe to find them
:)

See also

• A Field Guide to Elephpants


• ElePHPant - ElePHPant homepage.
• Logo éléPHPant - le film - A movie about ElePHPant creation.
• Official ElePHPant’s Facebook page
• PHP ElePHPant page - PHP.net’s page dedicated to ElePHPant informa-
tion.
• Seven PHP’s interview of Vincent Pontier

How to ask smart questions?


This guide will show you how to ask smart and efficient questions in technical
communities such as this.

205
Figure 39: Symfony ElePHPant

206
Figure 40: TrueNorth PHP Woolly Mammoth

Figure 41: PHP Classes ElePHPant

207
Figure 42: How to Ask Smart Questions

Research the problem

Figure 43: Research the problem

Read up on the problem before you ask for help. You may be able to save
the time of the helper, and even if your research doesn’t answer your questions,
you’ll be better able to convey these questions in a better, more sensible manner.
• Look for tutorials
• Do internet research
• Look at answers to other people’s questions on forums and answer sites
• Find and read documentation

Ask the right people

Finding the right channel with the right people is pretty important. Also con-
sider the complexity of the problem and the skill level of the people you wish
to ask.

208
Figure 44: Ask the right people

Figure 45: Don’t ask to ask

209
Don’t ask to ask

Ask your questions directly and clearly. Don’t worry about asking whether
it’s ok to ask a question. Any question is welcome, but you may be directed
elsewhere if the question is more appropriate to a different channel.

Figure 46: Ask everyone

Ask everyone

It’s not a good idea to address a question to a specific person, even if they’ve
helped you in the past. Directed questions are much less likely to be answered
than open questions.

Figure 47: Don’t ask when busy

Don’t ask when busy

Group can sometimes be flooded with questions or chatter. Try to find a differ-
ent channel where you can get the attention of people who’ll be able to help.

210
Figure 48: Be clear

Be clear

Make sure you write questions that clearly and concisely communicate the prob-
lems you want solved. This may include program version information and other
details about the system you’re using. For sharing code use nopaste.

Figure 49: Include purpose

Include purpose

Make sure to include the reason for your question and what you want to achieve
with the answer. This allows the person answering your question to provide the
right solution even when it isn’t obvious.

211
Figure 50: Be patient

Be patient

Wait for an answer. Not all group members are available all the time, but they’ll
respond when they can. Saying “thank you” when the question is solved can
give a much better impression about you and help to cultivate warm feelings for
those solving your question.
Keep learning; All experts were once beginners.

See also

Issues with asking questions are not new. Here are some more resources to study
how to ask questions in a smart and efficient way on the internet, specially in
technical communities.
• How to ask questions the smart way
• What have you tried?
• How to ask smart questions?
• StackOverflow: How do I ask a good question?

PHP podcasts

PHP related podcasts

• Lately in PHP

212
• PHP Podcasts
• PHP Roundtable
• PHP Town Hall
• PHPUgly Podcast

PHP framework related podcasts

• Laravel News Podcast


• Laravel Podcast
• Sound of Symfony

General

• /dev/hell

How to fix undefined variable/index notice?


A common notice when working with PHP can be:
Notice: Undefined variable: my_var in C:\xampp\htdocs\index.php on line 14
or
Notice: Undefined index: my_index C:\xampp\htdocs\index.php on line 24

Why does this happen?

You have some lines to set a variable or get posted data from a form like this:
$my_var = $_POST['myPostData'];
Now PHP does not have $_POST['myPostData'] if there is no POST data being
sent to the Page. This is when these errors come into play.

How to fix “Undefined variable”?

$my_var = ""; // Or $my_var = 0; for numbers to make sure the Variable is initialised
//now use isset()
$my_var = isset($_POST['myPostData']) ? $_POST['myPostData'] : "";
//or empty()
$my_var = !empty($_POST['myPostData']) ? $_POST['myPostData'] : "";

213
How to fix “Undefined index”?

//again we have two options here


//via array_key_exists()
$my_var = array_key_exists('my_index', $my_array) ? $my_array['my_index'] : "";
//or via isset()
$my_var = isset($my_array['my_index']) ? $my_array['my_index'] : "";
Note that array_key_exists() returns true when array has the specified key
ignoring its value while isset() returns true only if the specified key exists
and is not null.
$my_array = [];
$my_array['exists'] = null;
var_dump(array_key_exists('exists', $my_array));
var_dump(isset($my_array['exists']));
So, you should array_key_exists() only in situations which null val-
ues are relevant, otherwise use isset() because it is much faster than
array_key_exists().

Output

bool(true)
bool(false)

Null coalescing operator

Since PHP 7 there is also the ?? (or Null Coalescing) Operator available:
$my_var = $_POST['myPostData'] ?? "";

How to detect browser in PHP?


Sometimes you need to detect a user’s browser from PHP for the purposes of
displaying browser specific content or adjusting CSS & HTML.
PHP’s $_SERVER global variable holds browser’s ID information in
HTTP_USER_AGENT key: $_SERVER['HTTP_USER_AGENT'].
<?php
$userAgent = $_SERVER['HTTP_USER_AGENT'];

if (preg_match('/MSIE/i', $user_agent)) {
echo "Internet Explorer";

214
} else {
echo "Non-IE Browser";
}
Better alternative would be also to use PHP function get_browser:
<?php
$browser = get_browser(null, true);
print_r($browser);
Libraries to check out when you need some advanced functionalities:
• PHPBrowser

Where to get PHP certification?


If you decide to add an extra added value to your résumé, you should look into
PHP certifications. Many companies appreciate certifications since they can
prove you know more but these are still not the guarantee the knowledge can
be taken for granted.
For PHP specific field there is currently the following official PHP certification
available:
• PHP certification - official PHP certification

Other PHP certificates

There are also framework specific certifications available for different frameworks
and libraries available from their official vendors:
• Laravel certification - Certification for Laravel framework
• Magento certification - Magento ecommerce specific certification
• Symfony certification - Symfony framework speficic certification
• Twig certification - Certification for Twig template engine
• Zend Framework certification - Zend Framework 1 and 2 specific certifica-
tion
They can be taken online and quite a lot of preparation is required for them. In
case you decide to take any of the certification exams, make sure you prepare
well.

See also

• 7PHP: Exam Certification Tips

215
What is web crawling and how to crawl websites
with PHP?
Web crawling is automated process where a program is browsing World Wide
Web to index data from websites. Examples of web crawlers or web spiders are
Googlebot, bingbot and others.

See also

• PHPCrawl - Framework for crawling/spidering websites.


• spatie/crawler - Crawl all links found on a website.

How to work with date and time in PHP?


DateTime class provides a nice object oriented interface when working with date
and time. It has all the functionality of date functions and more. Therefore use
it and have consistency in parts of your code.
$date = DateTime::createFromFormat('Y-m-d', '2015-10-21');
echo $date->format('d.m.Y'); // 21.10.2015

Examples

Difference between dates with DateTime

$start = DateTime::createFromFormat('Y-m-d H:i:s', '2015-10-21 07:28:00');


$arrival = clone $start;
$arrival->add(new DateInterval('P1M6D')); // adds 1 month and 6 days

$diff = $arrival->diff($start);
echo $diff->format('%m month, %d days (total: %a days)'); // 1 month, 6 days (total: 37 days

Difference between dates with Carbon

Carbon is simple PHP API extension for DateTime. You will find it extremely
useful.
echo Carbon::now()->subMinutes(2)->diffForHumans(); // 2 minutes ago

216
Comparing dates

$now = new DateTime();


$arrival = DateTime::createFromFormat('Y-m-d', '2015-10-21');

if ($now == $arrival) {
echo "Welcome, Marty McFly!";
} else if ($now < $arrival) {
echo "Welcome to the future.";
} else {
echo "Welcome to the past.";
}

Time zone

Default time zone of DateTime::__construct() is the one from the system


PHP is currently running on. Good practice to avoid issues later on (when for
instance storing them in database and having users from different time zones)
is to always specify the UTC time zone:
// Construct a new UTC date
$date = new DateTime('now', new DateTimeZone('UTC'));

// Check current time in different time zones


$date = new DateTime('now', new DateTimeZone('Europe/London'));
echo $date->format('Y-m-d H:i:sP'); // 2015-10 07:28:00+01:00

$date->setTimezone(new DateTimeZone('Pacific/Chatham'));
echo $date->format('Y-m-d H:i:sP'); // 2015-10 07:28:00+13:45
Also don’t forget to set wanted time zone in php.ini files:
date.timezone = "UTC"

Localization

DateTime::format outputs everything only in English. Localization of date and


time formats can be done in two ways. With strftime() or IntlDateFormatter
which requires intl extension.
Using strftime:
setlocale(LC_TIME, "en_US");
$now = new DateTime('now');
echo strftime("%c", $now->getTimestamp()); // Wed Oct 21 07:28:00 2015

// change locale to Slovenian

217
setlocale(LC_TIME, "sl_SI");
echo strftime("%c", $now->getTimestamp()); // sre okt 21 07:28:00 2015 CEST
Using IntlDateFormatter:
$now = new DateTime('now');
$fmt = new IntlDateFormatter('en_US', IntlDateFormatter::FULL, IntlDateFormatter::FULL, 'Ame
echo $fmt->format($now); // Wednesday, October 21, 2015 at 07:28:00 AM Eastern Daylight Time

Quirks

Some strange quirks you might want to know and beware when dealing with
the following issues.

Zeroed dates
Zeroed dates (0000-00-00, 0000-00-00 00:00:00) can happen in MySQL for
example as the default value in columns with DateTime types. If you add zeroed
date to DateTime::__construct() they will result in nonsensical date:
$d = new DateTime("0000-00-00");
echo $d->format("Y-m-d"); // "-0001-11-30"

32-bit systems
On 32-bit systems DateTime::getTimestamp() will return false on dates beyond
2038.

DateTimeImmutable
When using setTimezone, setTimestamp, setDate, setTime, modify and some
other DateTime methods be careful because they will modify DateTime and
return $this. In below example you might expect that two objects below are
not the same:
function formatNextMondayFromNow(DateTime $dt) {
return $dt->modify('next monday')->format('Y-m-d');
}

$d = new DateTime();
echo formatNextMondayFromNow($d); // 2015-10-21
echo $d->format('Y-m-d'); // 2015-10-21
But they are because DateTime is mutable.
For that reason PHP 5.5 introduced DateTimeImmutable class which works the
same way as [DateTime] but it never changes itself. Instead it returns a new
object.

218
function formatNextMondayFromNow(DateTimeImmutable $dt) {
return $dt->modify('next monday')->format('Y-m-d');
}

$d = new DateTimeImmutable();
echo formatNextMondayFromNow($d); // 2015-10-26
echo $d->format('Y-m-d'); // 2015-10-21

See also

• Date and Time - PHP Manual - A must read to know more about date
and time in PHP.
• DateTimeImmutable blog post - Issue with some methods changing Date-
Time explained.

How to deploy PHP application?

Figure 51: PHP Deployment

Deployment of web applications is a process where application is uploaded from


your development machine or the source code repository (Git) to a web server
and is made accessible to users.
Deploying PHP application to production or staging environment might not be
so obvious task at first and requires some additional attention.

219
What does the deployment include?

During deployment, the source code files are transferred with some of the fol-
lowing additional steps:
• Checking out specific version of the application from the code repository
• Dependencies are installed with Composer
• Web assets (JavaScript, CSS, images) are generated, minified, concate-
nated…
• Database schema is migrated
• Cache is cleared
• Web server gets restarted
Modern deployments should be as simple, fast and be able to made often during
the application life time to meet the requirements. For example, if you change
only small portion of your code, only the changed files should be uploaded
and not all others. One of the modern deployment approaches is also atomic
deployment. It provides switching ability between different deployed versions
and web server uses symbolic link to the latest version location.

Quality

When uploading application from the development to production you also want
to ensure that tests pass and that application works as expected. This step adds
deploying application to another step, for example, a stage.

Application life cycle management (ALM)

Application life cycle generally consists of the following steps:


• Development
This is where you locally write code, integrate functionality, fix bugs, run tests,
commit and push code to a versioning system such as Git.
• Build
• Test
• Deploy

How to choose the right deployment strategy?

Pick the tools that you and your team find comfortable to work with and inspect
the available infrastructure options. You will not be able to use a single approach
for all of your projects. Many projects have their own edge cases and limits which
you must take into account when picking the build and deployment strategy.

220
FTP

Figure 52: FTP

FTP is the most basic file transfer approach you might have started with. It is
the easiest way of transferring application files to a web server by using FTP
protocol with some FTP client such as FileZilla or similar. FTP is simple and
convenient, but has many weaknesses such as security risks, lack of versioning
options and also it can be slow with a lot of files. Most shared hosting options
provide FTP to upload files to production.
The git-ftp provides Git version control system with FTP deployment.

Moving on

Below are listed some more advanced and convenient deployment methods. You
will need some prerequisite knowledge to link the basic deployment such as FTP
and further explained methods:
• Be able to use command line a lot. There is a really nice introduction
available in the art-of-command-line
• Be familiar with some basic DevOps skills.

221
System administration is often a very large chapter of its own and will not be
covered here in details.

GIT + SSH

When working with Git, you can use it to deploy your application as well.
In short the deployment procedure is the following:
• Local application development with Git
• Via SSH access you git pull and checkout possible specific application
version
If using GitHub, Bitbucket, GitLab or similar Git hosting service, you can add
the deployment SSH key in the repository.

Deployer

Deployer is a PHP cli application which can deploy your PHP application over
multiple protocols, SSH being widely used. After installation, a separate project
specific deploy.php file is used to deploy the application from the Git repository
to server via command line.
Pros:
• Completely customizable
• Fast
• Secure

Fabric

• Fabric is a widely used deployment tool written in Python. It works similar


as above explained Deployer, it is completely customizable, solid, fast and
secure.

Docker

Docker
Pros:
• Very modular
• Easier server management
Cons:

222
• Very high level DevOps knowledge is required to successfully deploy
projects with Docker.
Docker deployment strategy can be used in two ways:
• By building custom images with application code in the images and de-
ploying them to Docker Registry.
This is probably the most convenient way to use Docker in production. However
Docker Registry with custom images needs to be used.
• By using Git on the production server and using volumes for code. Images
can be build on the server itself or downloaded from Docker Registry.
Some useful resources to run Docker in production:
• Rancher
• Kubernetes

Jenkins

Jenkins provides continuous integration and can be used to deploy application


into production. The Jenkins ecosystem provides a multitude of plugins to
adjust your application life cycle to your needs. It can be even used together
with Docker to build images and run tasks in containers.

Other deployment options

• Envoy - A tool to run SSH tasks with PHP.


• Rocketeer - Deployment tool in PHP.
• Capistrano - Remote server automation and deployment tool in Ruby.
• Apache Ant - Java library and command line tool.
• Phing - PHP port of the Apache Ant.

Paid services

Some limited free and paid options you might want to check out if you want to
have more elegant and less “hacky” solutions:
• TeamCity - Proprietary deployment tool.
• DeployHQ - Web based GUI deployment service.
• Laravel Forge

223
PaaS

Platform as a Service include 3rd party services such as Heroku, Zeit, Azure
and others.

See also

To explore more about deployments, check also some of the following resources:
• Leanpub: Deploying PHP Applications
• Rasmus Lerdorf: Deploying PHP 7
• Servers for Hackers: Deployment
• Sitepoint: Easy Deployment of PHP Applications with Deployer
• Symfony deployment chapter
• Wikipedia: Continuous integration
• Wikipedia: List of build automation software

Can PHP be used for building desktop applica-


tions?
Building desktop applications with PHP language is not the usual way of creat-
ing such applications as is with C, C++, Java, C#, Python or others but yes
it can be done as well. Building desktop applications with PHP is useful for
having also server side part of the application covered with PHP also.

See also

• Phalanger - Phalanger is an open-source PHP implementation introducing


the PHP language into the family of compiled .NET languages.
• PHP Desktop - For Windows, native desktop GUI applications using web
technologies such as PHP, HTML5, JavaScript and SQLite.
• PHP GTK - Extension for PHP language that implements language bind-
ings for GTK+ and simplifies writing client-side cross-platform GUI ap-
plications.
• wxPHP - wxWidgets for PHP, binding/wrapper for the cross-platform
library wxWidgets, which gives you the ability to develop desktop appli-
cations using PHP.

224
How to send email with PHP?
Sending emails with PHP can be done with built-in mail function available in
PHP core. Building modern contact forms, customizing headers, sending HTML
emails, SMTP sending, local development, testing emails and other advanced
functionalities are sort of a must these days. That is why using libraries that
can help you get up to speed with emailing in PHP is recommended. There are
many competing open source libraries for sending emails with PHP available:
• PHPMailer
• Swift Mailer
• Zend\Mail

mail()

Let’s send simple email with built-in mail function:


<?php

$message = 'Hello, world.';

mail('receiver@example.com', 'My subject', $message);


Keep in mind that for above to work you will need to setup also mail server.

PHPMailer

Let’s look at a simple example to use PHPMailer and SMTP:


<?php

require 'PHPMailerAutoload.php';

$mail = new PHPMailer;

//$mail->SMTPDebug = 3; // Enable verbose debug output

$mail->isSMTP(); // Set mailer to use SMTP


$mail->Host = 'smtp1.example.com;smtp2.example.com'; // Specify main and backup SMTP server
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = 'user@example.com'; // SMTP username
$mail->Password = 'secret'; // SMTP password
$mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also a
$mail->Port = 587; // TCP port to connect to

225
$mail->From = 'from@example.com';
$mail->FromName = 'Mailer';
$mail->addAddress('joe@example.net', 'Joe User'); // Add a recipient
$mail->addAddress('ellen@example.com'); // Name is optional
$mail->addReplyTo('info@example.com', 'Information');
$mail->addCC('cc@example.com');
$mail->addBCC('bcc@example.com');

$mail->addAttachment('/var/tmp/file.tar.gz'); // Add attachments


$mail->addAttachment('/tmp/image.jpg', 'new.jpg'); // Optional name
$mail->isHTML(true); // Set email format to HTML

$mail->Subject = 'Here is the subject';


$mail->Body = 'This is the HTML message body <b>in bold!</b>';
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';

if(!$mail->send()) {
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
echo 'Message has been sent';
}

Swift Mailer

Let’s take the above example and refactor it to use the Swift Mailer library:
<?php

require_once 'lib/swift_required.php';

// Create the Transport


$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25)
->setUsername('your username')
->setPassword('your password')
;

/*
You could alternatively use a different transport such as Sendmail or Mail:

// Sendmail
$transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');

// Mail
$transport = Swift_MailTransport::newInstance();

226
*/

// Create the Mailer using your created Transport


$mailer = Swift_Mailer::newInstance($transport);

// Create a message
$message = Swift_Message::newInstance('Wonderful Subject')
->setFrom(['john@doe.com' => 'John Doe'])
->setTo(['receiver@domain.org', 'other@domain.org' => 'A name'])
->setBody('Here is the message itself')
;

// Send the message


$result = $mailer->send($message);

Zend Mail

In the following example we assume you know Zend Framework. Let’s send an
email with Zend Mail:
use Zend\Mail;

$mail = new Mail\Message();


$mail->setBody('This is the text of the email.');
$mail->setFrom('Freeaqingme@example.org', 'Sender\'s name');
$mail->addTo('Matthew@example.com', 'Name of recipient');
$mail->setSubject('TestSubject');

$transport = new Mail\Transport\Sendmail();


$transport->send($mail);

See also

Some other useful 3rd party services to check out when sending emails:
• Mandril
• SendGrid
• Mailgun

How to show and handle errors in PHP?


When you develop you will definitely want to turn on error reporting in PHP.
It gives you valuable information as to why something has failed. Let’s check
some of the most important error reporting directives in php.ini:

227
• error_reporting
This sets which errors should be reported. Using E_ALL is a good practice.
• display_errors
This handles displaying errors to the screen.
• log_errors
This controls reporting errors to a log file. Recommended practice is to
always have this enabled.
• error_log
This defines error log file where errors should be written. It only applies
if log_errors is enabled.
Showing errors should depend on the environment your application is present.

Development environment

When developing your application locally, you want to show errors on screen
and in logs.
display_errors = on
log_errors = on
error_reporting = E_ALL

Production environment

Be careful when deploying application code online. Disable showing errors on


screen for security purposes. You definitely don’t want to expose error messages
which can contain delicate information about your application to the outside
world. However, having logging errors enabled is always useful for information
about what went wrong in case of errors.
display_errors = off
log_errors = on
error_reporting = E_ALL
Error reporting can also be changed with the error_reporting() function.
error_reporting(0);

See also

• Error Handling and Logging - A must read PHP manual chapter about
configuring the error reporting in PHP.

228
• Error in PHP - PHP manual errors chapter.
• Monolog - Logging library for PHP.

How to detect face with PHP?


Face detection or other computer vision functionality are nicely solved by
OpenCV project.
Resources and PHP libraries:
• PHP Facedetect Extension - A simple OpenCV wrapper for PHP to detect
faces on images

$_GET vs $_POST?
Users often ask what are the differences between the $_GET and $_POST variables
in PHP and GET and POST HTTP methods in general.
First some background on the HTTP methods. GET and POST are two of many
HTTP methods (GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS,
CONNECT and PATCH) used to indicate the desired action to be performed
on the identified resourse.

GET method:

Query strings are sent in the URL of the GET request:


/test/form.php?name1=value1&name2=value2&name3=value3
You can then get the query strings in PHP like this:
<?php

$name1 = isset($_GET['name1']) ? $_GET['name1'] : null;


or
<?php

$name1 = filter_has_var(INPUT_GET, 'name1') ? filter_input(INPUT_GET, 'name1', FILTER_SANITI

POST method:

In case of POST method query strings are sent in the HTTP message body of
the POST request:

229
POST /test/form.php HTTP/1.1
Host: test.com

name1=value1&name2=value2&name3=value3
Query strings from the POST method can then be processed in PHP like this:
<?php

$name1 = isset($_POST['name1']) ? $_POST['name1'] : null;


or
$name1 = filter_has_var(INPUT_POST, 'name1') ? filter_input(INPUT_POST, 'name1', FILTER_SANI

The difference between using $_GET/$_POST and more verbose functions like
filter_*****() is - $_GET is superglobals variable and because it is a vari-
able it can be set to another value. It cannot be trusted to give actual values
came from HTTP header/body. - While functions like filter_has_var() or
filter_input() will always get the value from original HTTP header/body.
They can be trusted to give original values. - But filter_input() also has a
drawback. Because it rely on real user input, this can make testing/mocking
data harder.

Raw POST data

For POST method (or another method like PUT), you can get unprocessed
HTTP body like this:
<?php

$raw_body = file_get_contents('php://input');
This can be useful when you’re going to deal with incoming data which MIME
types is not application/x-www-form-urlencoded, like JSON data.
<?php

if (isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE'] === 'application/json') {


$post = json_decode(file_get_contents('php://input'), true) ?: array();
} else {
$post = $_POST;
}

230
How to fix Cannot modify header information -
headers already sent by… warning?
Common warning when working with PHP can be:
Warning: Cannot modify header information - headers already sent by (output started at /var/

Which functions usually produce this?

Functions that send or modify HTTP headers must be called before any output
is made:
• header
• header_remove
• session_regenerate_id
• session_start
• setcookie
• setrawcookie

Why this happens?

HTTP specification defines that HTTP headers must always be sent before the
output. PHP scripts mainly generate HTML content, but also pass a set of
HTTP/CGI headers to the webserver.
Usual HTTP response looks like this:
HTTP/1.1 200 OK
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8

<html>
<head>
<title>Example</title>
</head>
<body>
<h1>Page title</h1>
<p>After the two linebreaks HTTP response output is defined.</p>
In above case first three lines are HTTP headers and after two line breaks output
is defined. When PHP script receives the first output (html, output from echo
function etc) it will also flush all collected headers so far in the script procedure.
Afterwards it can send all the output it wants however adding other HTTP
headers will be impossible from there on.

231
Checklist of possible causes and how to fix it

• Whitespace or other ouput before the starting <?php tag or after closing
?> tag.
<?php

session_start();
• File where PHP code is used has UTF-8 Byte Order Mark. PHP files
should be encoded with UTF without BOM.
• Some previous error messages or notices are sent to the output.
• echo, print, printf or other printing functions produce output.
• Raw <html> sections prior to <?php code are written.

How to increase the upload file size in PHP?


Upload file size is defined in the PHP settings. Default PHP configuration values
are restricted to a maximum of 2 MB upload file size.
You can increase this limit in the php.ini file:
memory_limit = 128M
post_max_size = 12M
upload_max_filesize = 10M
Or in .htaccess file (if you’re using Apache and require per-directory settings):
php_value memory_limit 128M
php_value post_max_size 12M
php_value upload_max_filesize 10M
In above example we have increased file upload size from 2 MB to 10 MB. There
are also two additional directives - post_max_size and memory_limit. You will
have to increase post_max_size so that it is bigger than upload_max_size.
If the value of post_max_size is set larger than memory_limit, you will have
to increase also memory_limit. Recommendation is that memory_limit must
always be larger than post_max_size.
Changing ini directives can also be done by using PHP’s ini_set() function.
However this will not work for upload_max_filesize directive because it is
PHP_INI_PERDIR which cannot be changed at runtime. More about this is de-
scribed in the manual.
Keep in mind also that there are multiple php.ini files per PHP installation.
You can find out which ini files are loaded by executing php --ini in your
command line or going to a PHP information page generated by the phpinfo()
function.

232
See also

• Related FAQ: How to Securely Upload Files With PHP?

How to get client’s IP address in PHP?


When client connects to a webserver the IP address can get assigned by using
one of the HTTP headers. RFC 7239 standard specifies the Forwarded headers.
Many proxy servers and caching engines use also non standard but adopted by
practice the X-Forwarded-For HTTP header field to assign a comma and space
separated values of IP addresses (first one is the originating client).
The web server than assigns multiple possible global variables for client’s IP
address based on these headers and other information from the connecting client:
• $_SERVER['REMOTE_ADDR']
The global PHP variable which can contain the client’s IP address. This might
not be the real IP address from the client because it can be an internal IP
address from the LAN behind the proxy. In this case other variables might
contain the IP address.
• $_SERVER['X_FORWARDED_FOR'] or $_SERVER['HTTP_X_FORWARDED_FOR']
If a client is behind a proxy then the proxy might set the X_FORWARDED_FOR
HTTP header field, which can differ from the one in $_SERVER['REMOTE_ADDR'].
If you are saving the IP address to the database, saving both values is a
good idea. In some cases checking for presence of both X_FORWARDED_FOR and
HTTP_X_FORWARDED_FOR is important.
• Other non standard headers: In some cases some other non stan-
dard headers might also get set by some proxy servers and similar
devices. Examples of PHP global variables in such cases include:
$_SERVER['HTTP_CLIENT_IP'] and similar.
Relying on any of these to be the client’s real IP address is not certain.
If you are going to save the IP address to a database as a string, make sure you
have space for at least 45 characters. IPv4 is being replaced by a newer IPv6,
which has maximum length of 39 characters and IPv4-mapped IPv6 address has
maximum length of 45 characters. More and more servers are now getting the
IPv6 and those addresses are larger than the older IPv4 addresses.
A very simplified example of getting IP address from the client in PHP - beware
that validating the IP address is important in the last step since the HTTP
headers can be set to any arbitrary value:
<?php

233
// Get client's IP address
if (isset($_SERVER['HTTP_CLIENT_IP']) && array_key_exists('HTTP_CLIENT_IP', $_SERVER)) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && array_key_exists('HTTP_X_FORWARDED_FOR'
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$ips = array_map('trim', $ips);
$ip = $ips[0];
} else {
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}

$ip = filter_var($ip, FILTER_VALIDATE_IP);


$ip = ($ip === false) ? '0.0.0.0' : $ip;
Above example is very simplified and is shown here only as an introduction
into more usable components such as Symfony Http Foundation, Zend Http
Component and others.

See also

• The PHP IP Guide


• Symfony Http Foundation component - Implementation of getting user’s
IP in Symfony framework
• Wikipedia: X-Forwarded-For
• Zend Http Component - Implementation of getting user’s IP in Zend
Framework

How to detect ISP with PHP?


Getting ISP (internet service provider) of a client is possible with using geth-
ostbyaddr function which will attempt to retrieve clien’t host by its IP address:
Simple example:
<?php

$hostname = gethostbyaddr($_SERVER['REMOTE_ADDR']);

echo $hostname;
But important for you to know is that relying on this is not always possible
since the client may be logged in through VPN.

234
Open source licenses

What is a license and why should you pick one for your
project?

When open sourcing your code project you should always pick an appropriate
license for it.
There are a lot of open source licenses available that fit a lot of use cases.
• MIT License
• Creative Commons Attribution-ShareAlike 4.0 license

See also

• Coding Horror blog post


• Choose a license
• The MIT License, Line by Line
• TL;DR Legal

How to create Phar (PHP Archive)?

Packed php application archive

Note
"This action needs the php.ini setting phar.readonly to be set to 0 in order to work for Pha
PHAR (“Php ARchive”) is analogous to the JAR file concept but for PHP. If
you have PHP 5.3 or greater, the Phar extension is built-in and enabled; you
can start using it without any additional requirements. PHAR files are treated
as read-only by default, and you can use any PHAR file without any special
configuration. This is great for deployment. But as you’ll be creating your own
PHARs you’ll need to allow write-access which is done through the php.ini file.
Open php.ini, find the phar.readonly directive, and modify it accordingly:
phar.readonly = 0
Now you’re ready to package your libraries and applications as PHARs.
Below simple code can create phar from folder project or change it to your
project name.
<?php
// create with alias "project.phar"
$phar = new Phar('project.phar', 0, 'project.phar');
// add all files in the project

235
$phar->buildFromDirectory(dirname(__FILE__) . '/project');
$phar->setStub($phar->createDefaultStub('cli/index.php', 'www/index.php'));

$phar2 = new Phar('project2.phar', 0, 'project2.phar');


// add all files in the project, only include php files
$phar2->buildFromDirectory(dirname(__FILE__) . '/project', '/\.php$/');
$phar2->setStub($phar->createDefaultStub('cli/index.php', 'www/index.php'));

How to use PHP from the command-line?


PHP is mostly known to be used for writing web applications. But that is not
the whole picture of PHP language.
You can use PHP to write command-line applications as well.

See also

Some useful libraries:


• Cilex - Light-weight framework for creating command-line applications
• CLImate
• Hoa\Console
• PHP Shell Framework
• Symfony Console Component
• Webmozart Console

How to make readable, SEO friendly URLs in


PHP?
For the purposes of readability or SEO you will want to prettify URLs of your
web application to make them more descriptive. URL of a web application:
http://example.com/blog.php?id=21
In above example blog.php is the front controller or the main entry PHP file
which processes current request and id=21 is the query string which defines ID
of the blog post to show.
More user and SEO friendly URL would definitely be something like this:
http://example.com/blog/2015/11/20/awesome-blog-post

236
How to achieve this?

We want our front controller (index.php) to handle all requests that come to a
particular directory, except those that should go to an existing asset file such as
an image, CSS or JavaScript files. Also most PHP frameworks usually use this
single entry point approach for all URLs. First let’s configure web server a bit.

Apache

If you’re using Apache 2.2.16 or greater you can use FallbackResource direc-
tive:
In .htaccess add this:
FallbackResource index.php
If you are using Apache version prior to 2.2.16 or you will be doing a little more
complex stuff. For example, if you need to use RewriteBase, or maybe have
different rewrite conditions, you will have to use mod_rewrite rules. But in
most cases, only the FallbackResource will suffice and you can get also a bit
better performance.
If you still want to enable mod_rewrite and add some special rewrite rules in
.htaccess file, check the example below:
<IfModule mod_rewrite.c>
Options -MultiViews

RewriteEngine On
#RewriteBase /var/www/project/public
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
</IfModule>
On Linux machines you can activate mod_rewrite with a2enmod in command
line:
$ sudo a2enmod rewrite

Nginx

Here is an Nginx web server example for doing same requests handling as above.
In your Nginx site configuration file /etc/nginx/sites-available/default
enable PHP and requests handling. Here is minimum configuration to achieve
this:
server {
server_name domain.tld www.domain.tld;

237
root /var/www/project/public;

location / {
# try to serve file directly, fallback to app.php
try_files $uri /index.php$is_args$args;
}

location ~ ^/index\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/index.php/some-path
# Remove the internal directive to allow URIs like this
internal;
}

error_log /var/log/nginx/project_error.log;
access_log /var/log/nginx/project_access.log;
}

How to process request in PHP?

Now that we have web server set, we must process incoming request and do
the magic to show correct blog post. In this step the usual way of creating
web applications is to use a pattern such as MVC, MVP, MOVE or some other.
Below is a very simple way to parse URL with PHP. At the end we will list
some PHP libraries you should check out if you’re not planning to reinvent the
wheels here.
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

See also

Some other resources to check out here.


• FastRoute - Request router PHP library
• PHRoute - Request router PHP library

238
What is the difference between a developer and
programmer?
Developer is a person who solves problems and usually aren’t focused deeply
on the code unlike a programmer. They deal more with the project from a
bigger picture point of view. For example, they connect together different tech-
nologies and people involved in the project. They are responsible for organizing
the requirements and specifications of the project and deliver these to a pro-
grammer, who then implements them. Usually developers don’t need so much
programming skills.
Programmer is a person who writes programs based on the requirements or
specification they receive. They write beautiful code and have thorough knowl-
edge about a programming language, algorithms and how to do things really
well and optimized in code. Usually they don’t need people skills much.
Coder can be someone who writes code and deals directly with tasks that are
clearly defined and problems already recognized. For example, they create an
HTML and CSS layout of the website. Many times this title means the same as
programmer.
Architect is someone who looks at the big picture of the project. They need
management, people and general technology skills.
Important thing to understand is that many times these titles are also a matter
of a perspective and can be used interchangeably in the coding world. Sometimes
they are used to differentiate the responsibility, knowledge and skill levels. So
if you’re confused about this terminology, you can just refer to them all as
engineers.
Technology evangelist is someone who promotes particular technology or
product by blogging, conference and meetup talks, writing articles, sharing in-
formation on social networks and similar in order to convince other people to
use it as well.

Can you suggest some projects I can make?


In your learning path you should try developing some real projects. Project
complexity depends on what you want to achieve or your requirements from
your mentor at school or yourself. It doesn’t need to be a big project. A small
one will do to sharpen your knowledge.

See also

These links should help you in finding a project to make:

239
• App Specs - A curated list of applications specifications and implemen-
tations for practicing new technologies, improving your portfolio and
sharpen your skills.
• Project suggestions - A list of practical projects that anyone can solve in
any programming language.

Regex - regular expressions in PHP


Regular expressions (abbreviated regex) are sequences of characters that form
search patterns. They are mainly used in pattern matching with strings.

Brief history

• It started in 1940s-60s with lots of smart people talking about regular


expressions
• 1970s g/re/p
• 1980 Perl and Henry Spencer
• 1997 PCRE (Perl Compatible Regular Expressions) That’s where it really
took off and when we talk about regex today that’s what we’re talking
about. PCRE has libraries for almost every language, it looks the same
everywhere and it is very useful.

Common regex usage in PHP

PHP has three main regular expression PCRE functions - preg_match,


preg_match_all and preg_replace.

Matching

This returns 1 if match is found, 0 if not and false if error occurs:


int preg_match (
string $pattern,
string $subject [,
array &$matches [,
int $flags = 0 [,
int $offset = 0
]]])
This returns number of matches found:
int preg_match_all (
string $pattern,

240
string $subject [,
array &$matches [,
int $flags = PREG_PATTERN_ORDER [,
int $offset = 0
]]])

Replacing

This returns the replaced string or array (based on the $subject):


mixed preg_replace (
mixed $pattern,
mixed $replacement,
mixed $subject [,
int $limit = -1 [,
int $count
]])

Common regex usage in JavaScript

For comparison, regular expressions in JavaScript look pretty much the same as
in PHP.

Matching

Returns an array of matches or null if no matches were found:


string.match(RegExp);

Replacing

Returns the string with the replacements performed:


string.replace(RegExp, replacement);

Caveats of regex in JavaScript

• No “single-line” or DOTALL mode. (The dot never matches new line.)


• No lookbehind support
• Same methods for regex and non-regex matching and replacing

241
Basics of regex patterns

Let’s take a look at example to find email addresses in codebase. Our goal:
/[\w.+-]+@[a-z0-9-]+(\.[a-z0-9-]+)*/i

Sockets analogy

Regular expressions are built from two type of characters:


• special characters: .\[]?*+{}()^$/
• literals
Imagine your input strings as bolts and your pattern as a set of sockets (in
order).

Special characters
Let’s take a look at what special characters do:
• Backslash character \\ can escape other special character in regular ex-
pression:
• The Dot and the \w - .
Matches everything but new lines. If you want to match a dot and only a
dot escape it like \, \w matches letters, numbers, and the underscore
• Square brackets []
Matches characters inside the brackets. Supports ranges. Some examples:
– [abc] - matches any a, b or c.
– [a-z] Lowercase letters
– [0-9] Any single digit
– [a-zA-Z] - matches any lower or uppercase alphabetic character
• Optional ?
The ? matches 0 or 1
• The star *
The star matches 0 or more
• The Plus +
Matches 1 or more
• Curly brackets {}
Min and Max ranges. Some examples:
– {1,} at least 1

242
– {1,3} 1 through 3
– {1,64} 1 through 64
Let’s put all this together to get regex for email addresses:
/[\w.+-]+@[a-z0-9-]+(\.[a-z0-9-]+)*/i

Figure 53: Regex for email

How this looks in PHP:


preg_match_all(
"/[\w.+-]+@[a-z0-9-]+(\.[a-z0-9-]+)*/i",
$input_lines,
$output_array
);

Using regex for validation

Problem: make sure input is what we expect Goal 1: /[^\[\]\w$.]/ Goal 2:


/^[0-9]{1,2}[dwmy]$/
Regex is great at finding things but you need to know what you’re looking for.
When you validate you get to determine exactly what you want.

When not to use regex for validation?

Many cases are better handled with PHP’s filter_var function. For example
validating emails should be done with PHP built-in filters:
filter_var(
'bob@example.com',
FILTER_VALIDATE_EMAIL
)

243
Regex validation

For starting and ending regex you use anchors:


• ^ - the hat that indicates start of the string
• $ - the dollar sign that indicates end of string
if (!preg_match("%^[0-9]{1,2}[dwmy]$%", $_POST["subscription_frequency"])) {
$isError = true;
}
Negated character classes
• [^abc] - anything except a,b, or c, including new lines.
Example that ensures input only contains alphanumeric, dash, dot, underscore
if (preg_match("/[^0-9a-z-_.]/i", $productCode)) {
$isError = true;
}

Searching and replacing

Most common PCRE functions for performing search and replace are
preg_replace() and preg_replace_callback(). But there are also
preg_filter() and preg_replace_callback_array() to do almost the same.
Note that preg_replace_callback_array() is available since PHP7.

Replace words in the list with something

$subject = 'I want to eat some apples.';


echo preg_replace('/apple|banana|orange/', 'fruit', $subject);

Output
I want to eat some fruits.
If you have subpatterns (patterns in parentheses) in your pattern, you can use $N
or \N (where N is an integer >= 1) in replacement, this is called ‘backreference’.

Swap two numbers

$subject = '7/11';
echo preg_replace('/(\d+)\/(\d+)/', '$2/$1', $subject);

244
Output
11/7

Change date formatting

$subject = '2001-09-11';
echo preg_replace('/(\d+)\-(\d+)\-(\d+)/', '$3/$2/$1', $subject);

Output
11/09/2001

Simple example of replacing URL with <a> tag

$subject = 'Please visit https://php.earth/doc for more articles.';


echo preg_replace(
'#(https?\://([^\s\./]+(?:\.[^\s\./]+)*[^\s]*))#i',
'<a href="$1" target="_blank">$2</a>',
$subject
);

Output
Please visit <a href="https://php.earth/doc" target="_blank">php.earth/doc</a> for more arti
Sometimes you may want to perform complex search and replace like filter-
ing/sanitizing before replacing. This is a situation where preg_replace_callback()
may come into play.
In previous example our regex can replace only URLs begin with http or
https and now we want it to be able to replace URLs begin with www. too.
Someone might think we can simply change https?\:// into subpattern like
(?:https?\://|www\.) but this will not work in most browsers because they
will interprete www.domain as a relative path.
So we need to do some works before replacing, by prepending http:// if a URL
begins with www..
function add_protocol_if_begins_with_www($matches)
{
$url = strtolower($matches[1]) === 'www.'
? 'http://' . $matches[0]
: $matches[0];
return "<a href=\"{$url}\">{$matches[2]}</a>";
}

245
$subject = 'Please visit www.php.earth/doc for more articles.';
echo preg_replace_callback(
'#(https?\://|www\.)([^\s\./]+(?>\.[^\s\./]+)*[^\s]*)#i',
'add_protocol_if_begins_with_www',
$subject
);

Output
Please visit <a href="http://www.php.earth/doc" target="_blank">php.earth/doc</a> for more a
Problem: Link @mentions and #tags
Goal: /\B@([\w]{2,})/i

See also

• PHP.net resources:
• Pattern syntax
• Modifiers
• Functions
• Regex online tools:
• Debuggex - Online regex visualization tool.
• PHP Live Regex - Live regular expression tester for PHP.
• regexper - Regular expression visualizer using railroad diagrams.
• RegExr - Learn, build and test Regular Expressions.
• Regex101 - Create, debug, test and have your expressions explained for
PHP, PCRE, JavaScript and Python. The website also features a commu-
nity where you can share useful expressions.
• Tutorials:
• Demystifying RegEx with Practical Examples
• The best regex trick ever
• awesome-regex - A curated collection of awesome regex libraries, tools,
frameworks and software.
• RegexOne - Learn Regular Expressions with simple, interactive exercises.

What is web scraping and how to scrape data in


PHP?
Web scraping is a process of extracting data from a web document.
Two techniques used for scraping data from web documents are:

246
• Document parsing For example, HTML or XML document is converted
to DOM (Document Object Model). PHP offers DOM extension.
• Regular expressions To scrape data from web document also regular
expressions can be used.
Issue with scraping data from 3rd party websites is with copyrights if you don’t
have permissions to use that data. Another disadvantage is keeping up with
changes of the web document. Scraper must be adapted if that document
changes. For these reasons it is better to check and use API of website where
data needs to be scraped.

See also

• Goutte - simple PHP Web Scraper


• Simple HTML DOM Parser - PHP Simple HTML DOM Parser adaptation

How to take screenshot of a URL with PHP?

See also

• Snappy - PHP5 library allowing thumbnail, snapshot or PDF gen-


eration from an URL or a HTML page. Wrapper for wkhtml-
topdf/wkhtmltoimage.
• Webshots: Get a screenshot of a page using the plsein API
• WebThumbnail: Capture a screenshot of a page using WebThumbnail

Single vs double quotes in PHP

PHP Strings

Single quoted strings

• Will display things almost completely as is.


• Variables and most escape sequences will not be interpreted.
• The exception is that to display a literal single quote, you can escape it
with a back slash \',and to display a back slash, you can escape it with
another backslash \\.
Example:

247
$variable = 10;
echo 'Value is $variable';
Output:
Value is $variable

Double quote strings

• Will display a host of escaped characters (including some regexes), and


variables in the strings will be evaluated.
• An important point here is that you can use curly braces to isolate the
name of the variable you want evaluated.
Example:
$variable = 10;
echo "Value is $variable";
or
$variable = 10;
echo "Value is {$variable}";
Output:
Value is 10
When complex variable interpolation (array/object member accessing) is re-
quired it’s better to use curly braces.
Example:
echo "Value is {$arr[0]}";
echo "ID is {$obj->id}";
Variable interpolation with curly braces can also contain complex expressions
within accessors.
Example:
echo "Value is {$arr[max($min, $max)]}";

Heredoc

• Works like double quoted strings.


• It starts with <<<.
• After this operator, an identifier is provided, then a newline. The string
itself follows, and then the same identifier again to close the quotation.

248
• You don’t need to escape quotes in this syntax.

Nowdoc (since PHP 5.3.0)

• Works essentially like single quoted strings.


• The difference is that not even single quotes or backslashes have to be
escaped.
• A nowdoc is identified with the same <<< sequence used for heredocs, but
the identifier which follows is enclosed in single quotes, e.g. <<<'EOT'. No
parsing is done in nowdoc.

Credit

• Peter Ajtai - Stackoverflow Question

How to send SMS with PHP?


Sending SMS with web application can be useful for multiple purposes. For
instance you can increase security with integrate multi-factor authentication
system and increase security, retrieve forgotten passwords, send marketing mes-
sages, notify users about different events and similar.
Diagram below explains a simplified SMS sending flow where PHP application
communicates with SMS gateway which converts and forward received data to
SMS center (SMSC). SMSC routes data to mobile device (end user).

See also

• gnokii - Allows you to communicate with the phone.


• Kannel - Open Source WAP and SMS gateway.
• Nexmo - API for sending text messages.
• PHP Classes - Several solutions to send SMS with PHP.
• SMS Gateway
• SMS Gateway Android - Turn your Android phone into a SMS Gateway.
• PlaySMS - Free and Open Source SMS Gateway written in PHP based on
Gammu SMSD service.
• Twillio - API for sending text messages.
• Tutorials:
– Envato Tuts+ - How to Send Text Messages with PHP.
– SitePoint - Implement Two-way SMS with PHP.

249
Figure 54: Sending SMS with PHP

250
Which PHP template engine to use?
Business logic of an application determines how data are created, displayed,
stored and changed. Presentation layer determines how data are presented to
the user in certain format such as HTML, JSON, XML or some other.
Instead of mixing your application’s business logic and presentation and dupli-
cating code, best practice is to separate that with templates. Template engine
takes care of all that applies the Don’t Repeat Yourself (DRY) principle.
Example of a simple PHP template engine using Closure:
<?php

class Article
{
/**
* @var string
*/
private $title = 'This is an article';
}

class Post
{
/**
* @var string
*/
private $title = 'This is a post';
}

class Template
{
/**
* Renders template with closure.
*
* @param mixed $context
* @param string $template
*
* @return string
*/
public function render($context, $template)
{
$closure = function($template) {
ob_start();
include $template;
return ob_end_flush();
};

251
// Create a closure
$closure = $closure->bindTo($context, $context);
$closure($template);
}
}

$article = new Article();


$post = new Post();
$template = new Template();

$template->render($article, 'template.php');
$template->render($post, 'template.php');
Template file can be reused elsewhere:
<h1><?php echo $this->title;?></h1>
Template engines should also take care of XSS security vulnerability by escaping
data:
<?php echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8') ?>
Template engines can also feature template inheritance where child templates
extend parent ones:
layout.php:
<html lang="en">
<head>
<meta charset="utf-8">
<title><?=$title?></title>
</head>
<body>
<?=$this->section('body')?>
</body>
</html>
There is a wide variety of open source PHP templating engines:
• Aura.View (native)
• Blade (compiled, framework specific)
• Brainy (compiled)
• Dwoo (compiled)
• FigDice - compiled template rendering system
• Latte (compiled)
• Mustache (compiled)
• PHPTAL (compiled)
• Plates (native)
• Smarty (compiled)

252
• Transphporm - Innovative template engine which follows “template ani-
mation” approach. Template animation is using HTML/CSS… files as a
resource and manipulates them via the DOM to generate the dynamic
output.
• Twig (compiled)
• Zend\View (native, framework specific)

How to manage wildcard subdomains in PHP?


Wildcard subdomains are used for user specific sites, Deviantart, blogspot.com
are good examples. Usually DNS handles the subdomains depending on A and
CNAME records.
Using .htaccess will give control on incoming trafic (URL translation). Below
.htaccess code will redirect any subdomain to PHP page.
RewriteCond %{HTTP_HOST} !^www\.domain\.com
RewriteCond %{HTTP_HOST} ([^.]+)\.domain\.com [NC]
RewriteRule ^/?$ /member.php?username=%1 [L]
.htacces code will forward incoming request to member.php with GET
method. So anyone who types joy.domain.com will get content of
domain.com/member.php?username=joy. By using SQL query you can
verify if the username exists or not.
$sth = $dbh->prepare("SELECT * FROM user WHERE username=:username");
$sth->bindParam(':username', $username, PDO::PARAM_STR);
$sth->execute();
$result = $sth->fetch(PDO::FETCH_ASSOC);
if ($result) {
// show user data
} else {
// show 404 page
}

How to fix failed to open stream warning?


A common warning when working with PHP can be:
Warning: include(myinclude.php): failed to open stream: No such file or directory in myfile.

Why does this happen?

You have some lines to include a file like this:

253
include 'myinclude.php';
while your folder tree view is like this:
/includes/myinclude.php

index.php
Now PHP can not find the file myinclude.php because it is not in the same
directory as the index.php.

How to fix this?

A basic fix for this is setting the appropriate directory. For this example:
include 'includes/myinclude.php';

What if the included file is in a different subfolder then the


including file?

Sometimes we have a file tree view like this:


files/index.php

includes/myinclude.php
in this case a simple
include '../includes/myinclude.php';
would do the trick, however the best practice for this case is to use script dir
centric paths:
include __DIR__.'/../includes/myinclude.php';

What is the difference between a core PHP and


a vanilla/plain PHP?
While developing, there’s often a confusion between a core PHP and a
vanilla/plain PHP. This article will explain a difference between these terms
to avoid further confusion.

254
Core PHP

A core PHP describes the main engine of the PHP language itself and doesn’t
mean developing something with the PHP language directly. So a core PHP
developer writes C code and extends the PHP core or develops PHP extensions,
which are written in C programming language. Often times, core PHP is referred
to as PHP internals also.

Vanilla or plain PHP

A vanilla PHP or plain PHP is developing an application using the PHP lan-
guage without any 3rd party libraries or frameworks. So the vanilla developer
actually uses the language used in the name.

Conclusion

As long as you are writing PHP code, you are a vanilla PHP developer if you
are however writing on the PHP core itself, you can be considered a core PHP
developer.

See also

• PHP Internals Book


• What is the difference between a developer and programmer?

PHP best practices


• Introduction
• PHP setup
– PHP version
– PHP extensions
• Coding style
– Coding standards
– Arrays
– Ternary operator
• Composer
• Testing
• Emails
• Passwords
• Databases
• Security

255
– Secured configuration files
• Documentation
• Development environment

Introduction

In this section we will list some of the best PHP practices you should consider
adopting. PHP offers a lot of options and styles of writing your code. However,
as your application grows and becomes more complex, following best practices
is a must if you want modern and maintainable PHP code or simply want to be
a better PHP developer.

PHP setup

PHP version

Use the latest stable PHP version (i.e., PHP 7.1 at the time of writing this). You
will be able to use great new features and overall performance will be improved.
Using old versions can lead to security issues.

PHP extensions

For performance and security reasons, a good practice is to disable extensions


that you will not need in your production environment.

Coding style

Coding standards

Use PSR-1 and PSR-2 coding standards.

Arrays

Use short syntax for defining arrays:


$array = [
"foo" => "bar",
"bar" => "foo",
];

256
Ternary operator

In cases where you need to make a quick conditional check, there’s a ternary
operator that can make your code cleaner and more readable.
Let’s assume you want to set the $discount based on the value of the $amount.
If the $amount is less than 100, then the discount is 10%, and otherwise, it is
20%.
Say you want to check if the $amount variable equals 10, and if $amount equals
10 you want to set the $total to 1000, and if the $amount is NOT equal to 10
you want to set $total to 200.
You could use an if else statement:
<?php

if ($amount < 100) {


$discount = 10;
} else {
$discount = 20;
}
By using a ternary operator, you could write this in one line:
<?php

$discount = ($amount < 100) ? 10 : 20;


Note that in cases where you need to append a query if a certain condition is
met, an if statement would be a better choice.

Composer

In modern PHP, we should write less code, and since many problems have
already been solved, use existing solutions and libraries. Composer is a tool
for managing your dependencies in a PHP project. By using a terminal, you
can add, update, and remove dependent packages from packagist.org and other
repositories. Composer uses a composer.json file, located in your project di-
rectory, for managing dependent packages.

Testing

Always test your code. If you’re not familiar with concept of testing, start with
PHPUnit.

257
Emails

For sending emails there are multiple options in PHP, from using PHP’s default
mail() function, to external third-party libraries such as Swift Mailer and PHP-
Mailer. Try to avoid the default mail() function and instead use Swift Mailer
or PHPMailer. Building modern contact forms, customizing headers, sending
HTML emails, SMTP sending, different setups for sending emails in develop-
ment environments, testing emails and other advanced functionalities are sort
of a must these days, and the mail() function is too basic for that.

Passwords

Storing passwords must be done with PHP’s built-in password hashing API.

Databases

For databases, using PDO or simply just an ORM is very convenient and can
greatly help you handle advanced database manipulation tasks.
<?php
// PDO and MySQL example
$pdo = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
$statement = $pdo->query("SELECT id FROM friend");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['id']);

Security

Secured configuration files

Storing configuration files MUST be encapsulated.


return [
# Database Configuration
'database' => [
'hostname' => 'localhost',
'port' => 3306,
'username' => 'someone',
'password' => 'v3RyS3c|_|re'
],
];
<?php

$config = require __DIR__.'/relative/path/to/the/config.php';

258
Direct access to configuration files stored as formats such as JSON or YAML,
for example, should always be restricted by .htaccess:
#Apache 2.4+
Require local

#Before Apache 2.4


Order Deny,Allow
Deny from all
For Nginx servers, where .htaccess files aren’t used, the equivalent can be
achieved by using your nginx.conf file:
location /foo/bar/config.yml {
deny all;
}
When possible, for the best protection of configuration files, store them outside
of the publicly available document root.

Documentation

Always maintain documentation for your code. It adds extra time to your work,
but will be helpful to others (and also to you) in the future, to understand what
you’ve written. We forget what certain functions, methods and parts of code
do, so please always take extra time to document your work.
For inline PHP documentation, use phpDocumentor:
<?php

/**
* Foo file description.
*/

/**
* I belong to a class
*/
class Foo
{
}

Development environment

Don’t pick a premade *AMP (MAMP/LAMP/WAMP/XAMPP) stack. In-


stead, use virtualization software like Vagrant or Docker. Vagrant helps you

259
create and configure lightweight, reproducible, and portable development envi-
ronments. When using virtualization, make sure to create a virtual machine
that resembles the production server (the machine where you deploy). This will
help you catch deployment issues during the development stage. These articles
can help you get started with Vagrant and Docker in PHP development:
• 5 Easy Ways to Get Started with PHP on Vagrant
• Re-introducing Vagrant: The Right Way to Start with PHP
• Docker and dockerfiles made easy
Since the information provided on the article page may be outdated, you should
also refer to the official documentation for vagrant and docker, provided by the
application vendor.

260

Das könnte Ihnen auch gefallen