├── .gitignore ├── PHP_ The Right Way - phptherightway.com.azw3 ├── PHP_ The Right Way - phptherightway.com.epub ├── PHP_ The Right Way - phptherightway.com.mobi ├── PHP_ The Right Way - phptherightway.com.pdf ├── PHP_ The Right Way - phptherightway.com.txt ├── README.md ├── build-pdf.sh ├── php-the-right-way-06-21-2013.pdf └── php-the-right-way-06212013.html /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | -------------------------------------------------------------------------------- /PHP_ The Right Way - phptherightway.com.azw3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsd/php-the-right-way-pdf/fdf3c121eea1d71ff167cd88a8729281a643932e/PHP_ The Right Way - phptherightway.com.azw3 -------------------------------------------------------------------------------- /PHP_ The Right Way - phptherightway.com.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsd/php-the-right-way-pdf/fdf3c121eea1d71ff167cd88a8729281a643932e/PHP_ The Right Way - phptherightway.com.epub -------------------------------------------------------------------------------- /PHP_ The Right Way - phptherightway.com.mobi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsd/php-the-right-way-pdf/fdf3c121eea1d71ff167cd88a8729281a643932e/PHP_ The Right Way - phptherightway.com.mobi -------------------------------------------------------------------------------- /PHP_ The Right Way - phptherightway.com.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsd/php-the-right-way-pdf/fdf3c121eea1d71ff167cd88a8729281a643932e/PHP_ The Right Way - phptherightway.com.pdf -------------------------------------------------------------------------------- /PHP_ The Right Way - phptherightway.com.txt: -------------------------------------------------------------------------------- 1 | PHP: The Right Way 2 | 3 | • Getting Started 4 | 5 | – Use the Current Stable Version (5.4) 6 | 7 | – Built-in web server 8 | 9 | – Mac Setup 10 | 11 | – Windows Setup 12 | 13 | – Vagrant 14 | 15 | • Code Style Guide 16 | 17 | • Language Highlights 18 | 19 | – Programming Paradigms 20 | 21 | ∗ Object-oriented Programming 22 | 23 | ∗ Functional Programming 24 | 25 | ∗ Meta Programming 26 | 27 | – Namespaces 28 | 29 | – Standard PHP Library 30 | 31 | – Command Line Interface 32 | 33 | – XDebug 34 | 35 | • Dependency Management 36 | 37 | – Composer and Packagist 38 | 39 | ∗ How to Install Composer 40 | 41 | ∗ How to Install Composer (manually) 42 | 43 | ∗ How to Define and Install Dependencies 44 | 45 | ∗ Updating your dependencies 46 | 47 | ∗ Checking your dependencies for security issues 48 | 49 | – PEAR 50 | 51 | ∗ How to install PEAR 52 | 53 | ∗ How to install a package 54 | 55 | ∗ Handling PEAR dependencies with Composer 56 | 57 | • Coding Practices 58 | 59 | – The Basics 60 | 61 | – Date and Time 62 | 63 | 1 64 | 65 | – Design Patterns 66 | 67 | – Exceptions 68 | 69 | ∗ SPL Exceptions 70 | 71 | • Databases 72 | 73 | – PDO 74 | 75 | – Abstraction Layers 76 | 77 | • Security 78 | 79 | – Web Application Security 80 | 81 | – Password Hashing 82 | 83 | – Data Filtering 84 | 85 | ∗ Sanitization 86 | 87 | ∗ Validation 88 | 89 | – Configuration Files 90 | 91 | – Register Globals 92 | 93 | – Error Reporting 94 | 95 | ∗ Development 96 | 97 | ∗ Production 98 | 99 | • Testing 100 | 101 | – Test Driven Development 102 | 103 | ∗ Unit Testing 104 | 105 | ∗ Integration Testing 106 | 107 | ∗ Functional Testing 108 | 109 | – Behavior Driven Development 110 | 111 | ∗ BDD Links 112 | 113 | – Complementary Testing Tools 114 | 115 | ∗ Tool Links 116 | 117 | • Servers and Deployment 118 | 119 | – Platform as a Service (PaaS) 120 | 121 | – Virtual or Dedicated Servers 122 | 123 | ∗ nginx and PHP-FPM 124 | 125 | ∗ Apache and PHP 126 | 127 | – Shared Servers 128 | 129 | – Building and Deploying your Application 130 | 131 | ∗ Build Automation Tools 132 | 133 | ∗ Continuous Integration 134 | 135 | • Caching 136 | 137 | – Bytecode Cache 138 | 139 | 2 140 | 141 | – Object Caching 142 | 143 | • Resources 144 | 145 | – From the Source 146 | 147 | – People to Follow 148 | 149 | – Mentoring 150 | 151 | – PHP PaaS Providers 152 | 153 | – Frameworks 154 | 155 | – Components 156 | 157 | • Community 158 | 159 | – PHP User Groups 160 | 161 | – PHP Conferences 162 | 163 | – Created and maintained by 164 | 165 | – Project collaborators 166 | 167 | – Project contributors 168 | 169 | – Project sponsors 170 | 171 | Welcome 172 | 173 | There’s a lot of outdated information on the Web that leads new PHP users 174 | 175 | astray, propagating bad practices and bad code. This must stop. PHP: The 176 | 177 | Right Way is an easy-to-read, quick reference for PHP best practices, accepted 178 | 179 | coding standards, and links to authoritative tutorials around the Web. 180 | 181 | Getting Started 182 | 183 | Use the Current Stable Version (5.4) 184 | 185 | If you are just getting started with PHP make sure to start with the current 186 | 187 | stable release of PHP 5.4. PHP has made great strides adding powerful new features over the last few years. Don’t let the minor version number difference 188 | 189 | between 5.2 and 5.4 fool you, it represents major improvements. If you are 190 | 191 | looking for a function or it’s usage, the documentation on the php.net website will have the answer. 192 | 193 | Built-in web server 194 | 195 | You can start learning PHP without the hassle of installing and configuring a 196 | 197 | full-fledged web server (PHP 5.4 required). To start the server, run the following 198 | 199 | from your terminal in your project’s web root: 200 | 201 | 3 202 | 203 | > php -S localhost:8000 204 | 205 | • Learn about the built-in, command line web server 206 | 207 | Mac Setup 208 | 209 | OSX comes prepackaged with PHP but it is normally a little behind the latest 210 | 211 | stable. Lion comes with PHP 5.3.6 and Mountain Lion has 5.3.10. 212 | 213 | To update PHP on OSX you can get it installed through a number of Mac 214 | 215 | package managers, with php-osx by Liip being recommended. 216 | 217 | The other option is to compile it yourself, in that case be sure to have installed either Xcode or Apple’s substitute “Command Line Tools for Xcode” downloadable from Apple’s Mac Developer Center. 218 | 219 | For a complete “all-in-one” package including PHP, Apache web server and 220 | 221 | MySQL database, all this with a nice control GUI, try MAMP. 222 | 223 | Windows Setup 224 | 225 | PHP is available in several ways for Windows. You can download the binaries 226 | 227 | and until recently you could use a ‘.msi’ installer. The installer is no longer 228 | 229 | supported and stops at PHP 5.3.0. 230 | 231 | For learning and local development you can use the built in webserver with 232 | 233 | PHP 5.4 so you don’t need to worry about configuring it. If you would like an 234 | 235 | “all-in-one” which includes a full-blown webserver and MySQL too then tools 236 | 237 | such as the Web Platform Installer, Zend Server CE, XAMPP and WAMP will help get a Windows development environment up and running fast. That said, 238 | 239 | these tools will be a little different from production so be careful of environment 240 | 241 | differences if you are working on Windows and deploying to Linux. 242 | 243 | If you need to run your production system on Windows then IIS7 will give 244 | 245 | you the most stable and best performance. You can use phpmanager (a GUI plugin for IIS7) to make configuring and managing PHP simple. IIS7 comes 246 | 247 | with FastCGI built in and ready to go, you just need to configure PHP as a 248 | 249 | handler. For support and additional resources there is a dedicated area on iis.net 250 | 251 | for PHP. 252 | 253 | Vagrant 254 | 255 | Running your application on different environments in development and produc- 256 | 257 | tion can lead to strange bugs popping up when you go live. It’s also tricky to 258 | 259 | keep different development environments up to date with the same version for 260 | 261 | all libraries used when working with a team of developers. 262 | 263 | 4 264 | 265 | If you are developing on Windows and deploying to Linux (or anything non- 266 | 267 | Windows) or are developing in a team, you should consider using a virtual 268 | 269 | machine. This sounds tricky, but using Vagrant you can set up a simple virtual machine with only a few steps. These base boxes can then be set up manually, 270 | 271 | or you can use “provisioning” software such as Puppet or Chef to do this for you. 272 | 273 | Provisioning the base box is a great way to ensure that multiple boxes are set 274 | 275 | up in an identical fashion and removes the need for you to maintain complicated 276 | 277 | “set up” command lists. You can also “destroy” your base box and recreate it 278 | 279 | without many manual steps, making it easy to create a “fresh” installation. 280 | 281 | Vagrant creates shared folders used to share your code between your host and 282 | 283 | your virtual machine, meaning you can create and edit your files on your host 284 | 285 | machine and then run the code inside your virtual machine. 286 | 287 | Back to Top 288 | 289 | Code Style Guide 290 | 291 | The PHP community is large and diverse, composed of innumerable libraries, 292 | 293 | frameworks, and components. It is common for PHP developers to choose 294 | 295 | several of these and combine them into a single project. It is important that 296 | 297 | PHP code adhere (as close as possible) to a common code style to make it easy 298 | 299 | for developers to mix and match various libraries for their projects. 300 | 301 | The Framework Interop Group has proposed and approved a series of style recommendations, known as PSR-0, PSR-1 and PSR-2. Don’t let the funny names confuse you, these recommendations are merely a set of rules that some 302 | 303 | projects like Drupal, Zend, Symfony, CakePHP, phpBB, AWS SDK, FuelPHP, 304 | 305 | Lithium, etc are starting to adopt. You can use them for your own projects, or 306 | 307 | continue to use your own personal style. 308 | 309 | Ideally you should write PHP code that adheres to a known standard. This 310 | 311 | could be any combination of PSR’s, or one of the coding standards made by 312 | 313 | PEAR or Zend. This means other developers can easily read and work with your 314 | 315 | code, and applications that implement the components can have consistency 316 | 317 | even when working with lots of third-party code. 318 | 319 | • Read about PSR-0 320 | 321 | • Read about PSR-1 322 | 323 | • Read about PSR-2 324 | 325 | • Read about PEAR Coding Standards 326 | 327 | • Read about Zend Coding Standards 328 | 329 | You can use PHP_CodeSniffer to check code against any one of these recommendations, and plugins for text editors like Sublime Text 2 to be given real time feedback. 330 | 331 | 5 332 | 333 | Use Fabien Potencier’s PHP Coding Standards Fixer to automatically modify your code syntax so that it conforms with these standards, saving you from 334 | 335 | fixing each problem by hand. 336 | 337 | English is preferred for all symbol names and code infrastructure. Comments 338 | 339 | may be written in any language easily readable by all current and future parties 340 | 341 | who may be working on the codebase. 342 | 343 | Back to Top 344 | 345 | Language Highlights 346 | 347 | Programming Paradigms 348 | 349 | PHP is a flexible, dynamic language that supports a variety of programming 350 | 351 | techniques. It has evolved dramatically over the years, notably adding a solid 352 | 353 | object-oriented model in PHP 5.0 (2004), anonymous functions and namespaces 354 | 355 | in PHP 5.3 (2009), and traits in PHP 5.4 (2012). 356 | 357 | Object-oriented Programming 358 | 359 | PHP has a very complete set of object-oriented programming features including 360 | 361 | support for classes, abstract classes, interfaces, inheritance, constructors, cloning, 362 | 363 | exceptions, and more. 364 | 365 | • Read about Object-oriented PHP 366 | 367 | • Read about Traits 368 | 369 | Functional Programming 370 | 371 | PHP supports first-class function, meaning that a function can be assigned to 372 | 373 | a variable. Both user defined and built-in functions can be referenced by a 374 | 375 | variable and invoked dynamically. Functions can be passed as arguments to 376 | 377 | other functions (feature called Higher-order functions) and function can return 378 | 379 | other functions. 380 | 381 | Recursion, a feature that allows a function to call itself is supported by the 382 | 383 | language, but most of the PHP code focus on iteration. 384 | 385 | New anonymous functions (with support for closures) are present since PHP 5.3 386 | 387 | (2009). 388 | 389 | PHP 5.4 added the ability to bind closures to an object’s scope and also improved 390 | 391 | support for callables such that they can be used interchangeably with anonymous 392 | 393 | functions in almost all cases. 394 | 395 | 6 396 | 397 | • Continue reading on Functional Programming in PHP 398 | 399 | • Read about Anonymous Functions 400 | 401 | • Read about the Closure class 402 | 403 | • More details in the Closures RFC 404 | 405 | • Read about Callables 406 | 407 | • Read about dynamically invoking functions with call_user_func_array 408 | 409 | Meta Programming 410 | 411 | PHP supports various forms of meta programming through mechanisms like the 412 | 413 | Reflection API and Magic Methods. There are many Magic Methods available 414 | 415 | like __get(), __set(), __clone(), __toString(), __invoke(), etc. that allow 416 | 417 | developers to hook into class behavior. Ruby developers often say that PHP is 418 | 419 | lacking method_missing, but it is available as __call() and __callStatic(). 420 | 421 | • Read about Magic Methods 422 | 423 | • Read about Reflection 424 | 425 | Namespaces 426 | 427 | As mentioned above, the PHP community has a lot of developers creating lots 428 | 429 | of code. This means that one library’s PHP code may use the same class name 430 | 431 | as another library. When both libraries are used in the same namespace, they 432 | 433 | collide and cause trouble. 434 | 435 | Namespaces solve this problem. As described in the PHP reference manual, 436 | 437 | namespaces may be compared to operating system directories that namespace 438 | 439 | files; two files with the same name may co-exist in separate directories. Likewise, 440 | 441 | two PHP classes with the same name may co-exist in separate PHP namespaces. 442 | 443 | It’s as simple as that. 444 | 445 | It is important for you to namespace your code so that it may be used by other 446 | 447 | developers without fear of colliding with other libraries. 448 | 449 | One recommended way to use namespaces is outlined in PSR-0, which aims to provide a standard file, class and namespace convention to allow plug-and-play 450 | 451 | code. 452 | 453 | • Read about Namespaces 454 | 455 | • Read about PSR-0 456 | 457 | Standard PHP Library 458 | 459 | The Standard PHP Library (SPL) is packaged with PHP and provides a col- 460 | 461 | lection of classes and interfaces. It is made up primarily of commonly needed 462 | 463 | 7 464 | 465 | datastructure classes (stack, queue, heap, and so on), and iterators which can 466 | 467 | traverse over these datastructures or your own classes which implement SPL 468 | 469 | interfaces. 470 | 471 | • Read about the SPL 472 | 473 | Command Line Interface 474 | 475 | PHP was created primarily to write web applications, but it’s also useful for 476 | 477 | scripting command line interface (CLI) programs. Command line PHP programs 478 | 479 | can help you automate common tasks like testing, deployment, and application 480 | 481 | administrativia. 482 | 483 | CLI PHP programs are powerful because you can use your app’s code directly 484 | 485 | without having to create and secure a web GUI for it. Just be sure not to put 486 | 487 | your CLI PHP scripts in your public web root! 488 | 489 | Try running PHP from your command line: 490 | 491 | > php -i 492 | 493 | The -i option will print your PHP configuration just like the phpinfo function. 494 | 495 | The -a option provides an interactive shell, similar to ruby’s IRB or python’s 496 | 497 | interactive shell. There are a number of other useful command line options, too. 498 | 499 | Let’s write a simple “Hello, $name” CLI program. To try it out, create a file 500 | 501 | named hello.php, as below. 502 | 503 | php hello.php 528 | 529 | Usage: php hello.php [name] 530 | 531 | > php hello.php world 532 | 533 | Hello, world 534 | 535 | • Learn about running PHP from the command line 536 | 537 | • Learn about setting up Windows to run PHP from the command line 538 | 539 | XDebug 540 | 541 | One of the most useful tools in software development is a proper debugger. It 542 | 543 | allows you to trace the execution of your code and monitor the contents of the 544 | 545 | stack. XDebug, PHP’s debugger, can be utilized by various IDEs to provide 546 | 547 | Breakpoints and stack inspection. It can also allow tools like PHPUnit and 548 | 549 | KCacheGrind to perform code coverage analysis and code profiling. 550 | 551 | If you find yourself in a bind, willing to resort to var_dump/print_r, and you 552 | 553 | still can’t find the solution - maybe you need to use the debugger. 554 | 555 | Installing XDebug can be tricky, but one of its most important features is 556 | 557 | “Remote Debugging” - if you develop code locally and then test it inside a VM 558 | 559 | or on another server, Remote Debugging is the feature that you will want to 560 | 561 | enable right away. 562 | 563 | Traditionally, you will modify your Apache VHost or .htaccess file with these 564 | 565 | values: 566 | 567 | php_value xdebug.remote_host=192.168.?.? 568 | 569 | php_value xdebug.remote_port=9000 570 | 571 | The “remote host” and “remote port” will correspond to your local computer 572 | 573 | and the port that you configure your IDE to listen on. Then it’s just a matter 574 | 575 | of putting your IDE into “listen for connections” mode, and loading the URL: 576 | 577 | http://your-website.example.com/index.php?XDEBUG_SESSION_START=1 578 | 579 | Your IDE will now intercept the current state as the script executes, allowing 580 | 581 | you to set breakpoints and probe the values in memory. 582 | 583 | • Learn more about XDebug 584 | 585 | Back to Top 586 | 587 | 9 588 | 589 | Dependency Management 590 | 591 | There are a ton of PHP libraries, frameworks, and components to choose from. 592 | 593 | Your project will likely use several of them — these are project dependencies. 594 | 595 | Until recently, PHP did not have a good way to manage these project depen- 596 | 597 | dencies. Even if you managed them manually, you still had to worry about 598 | 599 | autoloaders. No more. 600 | 601 | Currently there are two major package management systems for PHP - Composer 602 | 603 | and PEAR. Which one is right for you? The answer is both. 604 | 605 | • Use Composer when managing dependencies for a single project. 606 | 607 | • Use PEAR when managing dependencies for PHP as a whole on your 608 | 609 | system. 610 | 611 | In general, Composer packages will be available only in the projects that you 612 | 613 | explicitly specify whereas a PEAR package would be available to all of your PHP 614 | 615 | projects. While PEAR might sound like the easier approach at first glance, there 616 | 617 | are advantages to using a project-by-project approach to your dependencies. 618 | 619 | Composer and Packagist 620 | 621 | Composer is a brilliant dependency manager for PHP. List your project’s depen- 622 | 623 | dencies in a composer.json file and, with a few simple commands, Composer 624 | 625 | will automatically download your project’s dependencies and setup autoloading 626 | 627 | for you. 628 | 629 | There are already a lot of PHP libraries that are compatible with Composer, 630 | 631 | ready to be used in your project. These “packages” are listed on Packagist, the official repository for Composer-compatible PHP libraries. 632 | 633 | How to Install Composer 634 | 635 | You can install Composer locally (in your current working directory; though this 636 | 637 | is no longer recommended) or globally (e.g. /usr/local/bin). Let’s assume you 638 | 639 | want to install Composer locally. From your project’s root directory: 640 | 641 | curl -s https://getcomposer.org/installer | php 642 | 643 | This will download composer.phar (a PHP binary archive). You can run this 644 | 645 | with php to manage your project dependencies. Please Note: If you pipe 646 | 647 | downloaded code directly into an interpreter, please read the code online first to 648 | 649 | confirm it is safe. 650 | 651 | 10 652 | 653 | How to Install Composer (manually) 654 | 655 | Manually installing Composer is an advanced technique; however, there are 656 | 657 | various reasons why a developer might prefer this method vs. using the interactive 658 | 659 | installation routine. The interactive installation checks your PHP installation to 660 | 661 | ensure that: 662 | 663 | • a sufficient version of PHP is being used 664 | 665 | • .phar files can be executed correctly 666 | 667 | • certain directory permissions are sufficient 668 | 669 | • certain problematic extensions are not loaded 670 | 671 | • certain php.ini settings are set 672 | 673 | Since a manual installation performs none of these checks, you have to decide 674 | 675 | whether the trade-off is worth it for you. As such, below is how to obtain 676 | 677 | Composer manually: 678 | 679 | curl -s https://getcomposer.org/composer.phar -o $HOME/local/bin/composer 680 | 681 | chmod +x $HOME/local/bin/composer 682 | 683 | The path $HOME/local/bin (or a directory of your choice) should be in your 684 | 685 | $PATH environment variable. This will result in a composer command being 686 | 687 | available. 688 | 689 | When you come across documentation that states to run Composer as php 690 | 691 | composer.phar install, you can substitute that with: 692 | 693 | composer install 694 | 695 | How to Define and Install Dependencies 696 | 697 | Composer keeps track of your project’s dependencies in a file called 698 | 699 | composer.json. You can manage it by hand if you like, or use Composer itself. 700 | 701 | The php composer.phar require command adds a project dependency and if 702 | 703 | you don’t have a composer.json file, one will be created. Here’s an example 704 | 705 | that adds Twig as a dependency of your project. Run it in your project’s root directory where you’ve downloaded composer.phar: 706 | 707 | php composer.phar require twig/twig:~1.8 708 | 709 | Alternatively the php composer.phar init command will guide you through 710 | 711 | creating a full composer.json file for your project. Either way, once you’ve 712 | 713 | created your composer.json file you can tell Composer to download and install 714 | 715 | your dependencies into the vendors/ directory. This also applies to projects 716 | 717 | you’ve downloaded that already provide a composer.json file: 718 | 719 | 11 720 | 721 | php composer.phar install 722 | 723 | Next, add this line to your application’s primary PHP file; this will tell PHP to 724 | 725 | use Composer’s autoloader for your project dependencies. 726 | 727 | format('m/d/Y') . "\n"; 914 | 915 | Calculating with DateTime is possible with the DateInterval class. DateTime 916 | 917 | has methods like add() and sub() that take a DateInterval as an argument. Do 918 | 919 | not write code that expect same number of seconds in every day, both daylight 920 | 921 | saving and timezone alterations will break that assumption. Use date intervals 922 | 923 | instead. To calculate date difference use the diff() method. It will return new 924 | 925 | DateInterval, which is super easy to display. 926 | 927 | add(new \DateInterval('P1M6D')); 934 | 935 | $diff = $end->diff($start); 936 | 937 | echo 'Difference: ' . $diff->format('%m month, %d days (total: %a days)') . "\n"; 938 | 939 | // Difference: 1 month, 6 days (total: 37 days) 940 | 941 | On DateTime objects you can use standard comparison: 942 | 943 | format('m/d/Y') . ' '; 968 | 969 | } 970 | 971 | 15 972 | 973 | • Read about DateTime 974 | 975 | • Read about date formatting (accepted date format string options) 976 | 977 | Design Patterns 978 | 979 | When you are building your application it is helpful to use common patterns in 980 | 981 | your code and common patterns for the overall structure of your project. Using 982 | 983 | common patterns is helpful because it makes it much easier to manage your code 984 | 985 | and lets other developers quickly understand how everything fits together. 986 | 987 | If you use a framework then most of the higher level code and project structure 988 | 989 | will be based on that framework, so a lot of the pattern decisions are made for 990 | 991 | you. But it is still up to you to pick out the best patterns to follow in the code 992 | 993 | you build on top of the framework. If, on the other hand, you are not using a 994 | 995 | framework to build your application then you have to find the patterns that best 996 | 997 | suit the type and size of application that you’re building. 998 | 999 | • Continue reading on Design Patterns 1000 | 1001 | Exceptions 1002 | 1003 | Exceptions are a standard part of most popular programming languages, but they 1004 | 1005 | are often overlooked by PHP programmers. Languages like Ruby are extremely 1006 | 1007 | Exception heavy, so whenever something goes wrong such as a HTTP request 1008 | 1009 | failing, or a DB query goes wrong, or even if an image asset could not be found, 1010 | 1011 | Ruby (or the gems being used) will throw an exception to the screen meaning 1012 | 1013 | you instantly know there is a mistake. 1014 | 1015 | PHP itself is fairly lax with this, and a call to file_get_contents() will 1016 | 1017 | usually just get you a FALSE and a warning. Many older PHP frameworks like 1018 | 1019 | CodeIgniter will just return a false, log a message to their proprietary logs and 1020 | 1021 | maybe let you use a method like $this->upload->get_error() to see what 1022 | 1023 | went wrong. The problem here is that you have to go looking for a mistake and 1024 | 1025 | check the docs to see what the error method is for this class, instead of having it 1026 | 1027 | made extremely obvious. 1028 | 1029 | Another problem is when classes automatically throw an error to the screen 1030 | 1031 | and exit the process. When you do this you stop another developer from being 1032 | 1033 | able to dynamically handle that error. Exceptions should be thrown to make a 1034 | 1035 | developer aware of an error, then they can choose how to handle this. E.g: 1036 | 1037 | subject('My Subject'); 1042 | 1043 | $email->body('How the heck are you?'); 1044 | 1045 | 16 1046 | 1047 | $email->to('guy@example.com', 'Some Guy'); 1048 | 1049 | try 1050 | 1051 | { 1052 | 1053 | $email->send(); 1054 | 1055 | }catch(Fuel\Email\ValidationFailedException $e) 1056 | 1057 | { 1058 | 1059 | // The validation failed 1060 | 1061 | }catch(Fuel\Email\SendingFailedException $e) 1062 | 1063 | { 1064 | 1065 | // The driver could not send the email 1066 | 1067 | } 1068 | 1069 | SPL Exceptions 1070 | 1071 | The generic Exception class provides very little debugging context for the devel- 1072 | 1073 | oper; however, to remedy this, it is possible to create a specialized Exception 1074 | 1075 | type by sub-classing the generic Exception class: 1076 | 1077 | query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO! 1176 | 1177 | This is terrible code. 1178 | 1179 | You are inserting a raw query parameter into 1180 | 1181 | a SQL query. 1182 | 1183 | This will get you hacked in a heartbeat. 1184 | 1185 | Just imag- 1186 | 1187 | ine if a hacker passes in an inventive id parameter by calling a URL 1188 | 1189 | like http://domain.com/?id=1%3BDELETE+FROM+users. 1190 | 1191 | This will set the 1192 | 1193 | $_GET[’id’] variable to 1;DELETE FROM users which will delete all of your 1194 | 1195 | users! Instead, you should sanitize the ID input using PDO bound parameters. 1196 | 1197 | 18 1198 | 1199 | prepare('SELECT name FROM users WHERE id = :id'); 1204 | 1205 | $stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); //<-- Automatically sanitized by PDO 1206 | 1207 | $stmt->execute(); 1208 | 1209 | This is correct code. It uses a bound parameter on a PDO statement. This 1210 | 1211 | escapes the foreign input ID before it is introduced to the database preventing 1212 | 1213 | potential SQL injection attacks. 1214 | 1215 | • Learn about PDO 1216 | 1217 | You should also be aware that database connections use up resources and it was 1218 | 1219 | not unheard-of to have resources exhausted if connections were not implicitly 1220 | 1221 | closed, however this was more common in other languages. Using PDO you can 1222 | 1223 | implicitly close the connection by destroying the object by ensuring all remaining 1224 | 1225 | references to it are deleted, ie. set to NULL. If you don’t do this explicitly, PHP 1226 | 1227 | will automatically close the connection when your script ends unless of course 1228 | 1229 | you are using persistent connections. 1230 | 1231 | • Learn about PDO connections 1232 | 1233 | Abstraction Layers 1234 | 1235 | Many frameworks provide their own abstraction layer which may or may not 1236 | 1237 | sit on top of PDO. These will often emulate features for one database system 1238 | 1239 | that another is missing from another by wrapping your queries in PHP methods, 1240 | 1241 | giving you actual database abstraction. This will of course add a little overhead, 1242 | 1243 | but if you are building a portable application that needs to work with MySQL, 1244 | 1245 | PostgreSQL and SQLite then a little overhead will be worth it the sake of code 1246 | 1247 | cleanliness. 1248 | 1249 | Some abstraction layers have been built using the PSR-0 namespace standard so 1250 | 1251 | can be installed in any application you like: 1252 | 1253 | • Aura SQL 1254 | 1255 | • Doctrine2 DBAL 1256 | 1257 | • ZF2 Db 1258 | 1259 | • ZF1 Db 1260 | 1261 | Back to Top 1262 | 1263 | 19 1264 | 1265 | Security 1266 | 1267 | Web Application Security 1268 | 1269 | There are bad people ready and willing to exploit your web application. It is 1270 | 1271 | important that you take necessary precautions to harden your web application’s 1272 | 1273 | security. Luckily, the fine folks at The Open Web Application Security Project 1274 | 1275 | (OWASP) have compiled a comprehensive list of known security issues and 1276 | 1277 | methods to protect yourself against them. This is a must read for the security- 1278 | 1279 | conscious developer. 1280 | 1281 | • Read the OWASP Security Guide 1282 | 1283 | Password Hashing 1284 | 1285 | Eventually everyone builds a PHP application that relies on user login. User- 1286 | 1287 | names and passwords are stored in a database and later used to authenticate 1288 | 1289 | users upon login. 1290 | 1291 | It is important that you properly hash passwords before storing them. Password hashing is an irreversible, one way function performed against the users password. 1292 | 1293 | This produces a fixed-length string that can not be feasibly reversed. This means 1294 | 1295 | you can compare a hash against another to determine if they both came from the 1296 | 1297 | same source string, but you can not determine the original string. If passwords 1298 | 1299 | are not hashed and your database is accessed by an unauthorized third-party, 1300 | 1301 | all user accounts are now compromised. Some users may (unfortunately) use 1302 | 1303 | the same password for other services. Therefore, it is important to take security 1304 | 1305 | seriously. 1306 | 1307 | Hashing passwords with password_hash 1308 | 1309 | In PHP 5.5 password_hash will be introduced. At this time it is using BCrypt, 1310 | 1311 | the strongest algorithm currently supported by PHP. It will be updated in the 1312 | 1313 | future to support more algorithms as needed though. The password_compat 1314 | 1315 | library was created to provide forward compatibility for PHP >= 5.3.7. 1316 | 1317 | Below we hash a string, we then check the hash against a new string. Because 1318 | 1319 | our two source strings are different (‘secret-password’ vs. ‘bad-password’) this 1320 | 1321 | login will fail. 1322 | 1323 | = 5.3.7 && < 5.5 1344 | 1345 | • Learn about hashing in regards to cryptography 1346 | 1347 | • PHP password_hash RFC 1348 | 1349 | Data Filtering 1350 | 1351 | Never ever (ever) trust foreign input introduced to your PHP code. Always 1352 | 1353 | sanitize and validate foreign input before using it in code. The filter_var and 1354 | 1355 | filter_input functions can sanitize text and validate text formats (e.g. email 1356 | 1357 | addresses). 1358 | 1359 | Foreign input can be anything: $_GET and $_POST form input data, some 1360 | 1361 | values in the $_SERVER superglobal, and the HTTP request body via 1362 | 1363 | fopen(’php://input’, ’r’). Remember, foreign input is not limited to form 1364 | 1365 | data submitted by the user. Uploaded and downloaded files, session values, 1366 | 1367 | cookie data, and data from third-party web services are foreign input, too. 1368 | 1369 | While foreign data can be stored, combined, and accessed later, it is still foreign 1370 | 1371 | input. Every time you process, output, concatenate, or include data in your 1372 | 1373 | code, ask yourself if the data is filtered properly and can it be trusted. 1374 | 1375 | Data may be filtered differently based on its purpose. For example, when 1376 | 1377 | unfiltered foreign input is passed into HTML page output, it can execute HTML 1378 | 1379 | and JavaScript on your site! This is known as Cross-Site Scripting (XSS) and 1380 | 1381 | can be a very dangerous attack. One way to avoid XSS is to sanitize all user- 1382 | 1383 | generated data before outputting it to your page by removing HTML tags 1384 | 1385 | with the strip_tags function or escaping characters with special meaning into 1386 | 1387 | their respective HTML entities with the htmlentities or htmlspecialchars 1388 | 1389 | functions. 1390 | 1391 | Another example is passing options to be executed on the command line. This can 1392 | 1393 | be extremely dangerous (and is usually a bad idea), but you can use the built-in 1394 | 1395 | escapeshellarg function to sanitize the executed command’s arguments. 1396 | 1397 | One last example is accepting foreign input to determine a file to load from the 1398 | 1399 | filesystem. This can be exploited by changing the filename to a file path. You 1400 | 1401 | need to remove ”/”, “../”, null bytes, or other characters from the file path so it can’t load hidden, non-public, or sensitive files. 1402 | 1403 | • Learn about data filtering 1404 | 1405 | 21 1406 | 1407 | • Learn about filter_var 1408 | 1409 | • Learn about filter_input 1410 | 1411 | • Learn about handling null bytes 1412 | 1413 | Sanitization 1414 | 1415 | Sanitization removes (or escapes) illegal or unsafe characters from foreign input. 1416 | 1417 | For example, you should sanitize foreign input before including the input in 1418 | 1419 | HTML or inserting it into a raw SQL query. When you use bound parameters 1420 | 1421 | with PDO, it will sanitize the input for you. 1422 | 1423 | Sometimes it is required to allow some safe HTML tags in the input when 1424 | 1425 | including it in the HTML page. This is very hard to do and many avoid it by 1426 | 1427 | using other more restricted formatting like Markdown or BBCode, although 1428 | 1429 | whitelisting libraries like HTML Purifier exists for this reason. 1430 | 1431 | See Sanitization Filters 1432 | 1433 | Validation 1434 | 1435 | Validation ensures that foreign input is what you expect. For example, you may 1436 | 1437 | want to validate an email address, a phone number, or age when processing a 1438 | 1439 | registration submission. 1440 | 1441 | See Validation Filters 1442 | 1443 | Configuration Files 1444 | 1445 | When creating configuration files for your applications, best practices recommend 1446 | 1447 | that one of the following methods be followed: 1448 | 1449 | • It is recommended that you store your configuration information where it 1450 | 1451 | cannot be accessed directly and pulled in via the file system. 1452 | 1453 | • If you must store your configuration files in the document root, name the 1454 | 1455 | files with a .php extension. This ensures that, even if the script is accessed 1456 | 1457 | directly, it will not be outputed as plain text. 1458 | 1459 | • Information in configuration files should be protected accordingly, either 1460 | 1461 | through encryption or group/user file system permissions 1462 | 1463 | Register Globals 1464 | 1465 | NOTE: As of PHP 5.4.0 the register_globals setting has been removed and 1466 | 1467 | can no longer be used. This is only included as a warning for anyone in the 1468 | 1469 | process of upgrading a legacy application. 1470 | 1471 | 22 1472 | 1473 | When enabled, the register_globals configuration setting that makes several 1474 | 1475 | types of variables (including ones from $_POST, $_GET and $_REQUEST) available 1476 | 1477 | in the global scope of your application. This can easily lead to security issues as 1478 | 1479 | your application cannot effectively tell where the data is coming from. 1480 | 1481 | For example: $_GET[’foo’] would be available via $foo, which can override 1482 | 1483 | variables that have not been declared. If you are using PHP < 5.4.0 make sure 1484 | 1485 | that register_globals is off. 1486 | 1487 | • Register_globals in the PHP manual 1488 | 1489 | Error Reporting 1490 | 1491 | Error logging can be useful in finding the problem spots in your application, 1492 | 1493 | but it can also expose information about the structure of your application to 1494 | 1495 | the outside world. To effectively protect your application from issues that could 1496 | 1497 | be caused by the output of these messages, you need to configure your server 1498 | 1499 | differently in development versus production (live). 1500 | 1501 | Development 1502 | 1503 | To show every possible error during development, configure the following 1504 | 1505 | settings in your php.ini: 1506 | 1507 | display_errors = On 1508 | 1509 | display_startup_errors = On 1510 | 1511 | error_reporting = -1 1512 | 1513 | log_errors = On 1514 | 1515 | Passing in the value -1 will show every possible error, even when new 1516 | 1517 | levels and constants are added in future PHP versions. The E_ALL 1518 | 1519 | constant also behaves this way as of PHP 5.4. - php.net 1520 | 1521 | The E_STRICT error level constant was introduced in 5.3.0 and is not part of 1522 | 1523 | E_ALL, however it became part of E_ALL in 5.4.0. What does this mean? In 1524 | 1525 | terms of reporting every possible error in version 5.3 it means you must use 1526 | 1527 | either -1 or E_ALL | E_STRICT. 1528 | 1529 | Reporting every possible error by PHP version 1530 | 1531 | • < 5.3 -1 or E_ALL 1532 | 1533 | • 1534 | 1535 | 5.3 -1 or E_ALL | E_STRICT 1536 | 1537 | • > 5.3 -1 or E_ALL 1538 | 1539 | 23 1540 | 1541 | Production 1542 | 1543 | To hide errors on your production environment, configure your php.ini as: 1544 | 1545 | display_errors = Off 1546 | 1547 | display_startup_errors = Off 1548 | 1549 | error_reporting = E_ALL 1550 | 1551 | log_errors = On 1552 | 1553 | With these settings in production, errors will still be logged to the error logs 1554 | 1555 | for the web server, but will not be shown to the user. For more information on 1556 | 1557 | these settings, see the PHP manual: 1558 | 1559 | • error_reporting 1560 | 1561 | • display_errors 1562 | 1563 | • display_startup_errors 1564 | 1565 | • log_errors 1566 | 1567 | Back to Top 1568 | 1569 | Testing 1570 | 1571 | Writing automated tests for your PHP code is considered a best practice and 1572 | 1573 | can lead to well-built applications. Automated tests are a great tool for making 1574 | 1575 | sure your application does not break when you are making changes or adding 1576 | 1577 | new functionality and should not be ignored. 1578 | 1579 | There are several different types of testing tools (or frameworks) available for 1580 | 1581 | PHP, which use different approaches - all of which are trying to avoid manual 1582 | 1583 | testing and the need for large Quality Assurance teams, just to make sure recent 1584 | 1585 | changes didn’t break existing functionality. 1586 | 1587 | Test Driven Development 1588 | 1589 | From Wikipedia: 1590 | 1591 | Test-driven development (TDD) is a software development process 1592 | 1593 | that relies on the repetition of a very short development cycle: first 1594 | 1595 | the developer writes a failing automated test case that defines a 1596 | 1597 | desired improvement or new function, then produces code to pass 1598 | 1599 | that test and finally refactors the new code to acceptable standards. 1600 | 1601 | Kent Beck, who is credited with having developed or ‘rediscovered’ 1602 | 1603 | the technique, stated in 2003 that TDD encourages simple designs 1604 | 1605 | and inspires confidence 1606 | 1607 | 24 1608 | 1609 | There are several different types of testing that you can do for your application 1610 | 1611 | Unit Testing 1612 | 1613 | Unit Testing is a programming approach to ensure functions, classes and methods 1614 | 1615 | are working as expected, from the point you build them all the way through the 1616 | 1617 | development cycle. By checking values going in and out of various functions and 1618 | 1619 | methods, you can make sure the internal logic is working correctly. By using 1620 | 1621 | Dependency Injection and building “mock” classes and stubs you can verify that 1622 | 1623 | dependencies are correctly used for even better test coverage. 1624 | 1625 | When you create a class or function you should create a unit test for each 1626 | 1627 | behavior it must have. At a very basic level you should make sure it errors if 1628 | 1629 | you send it bad arguments and make sure it works if you send it valid arguments. 1630 | 1631 | This will help ensure that when you make changes to this class or function 1632 | 1633 | later on in the development cycle that the old functionality continues to work 1634 | 1635 | as expected. The only alternative to this would be var_dump() in a test.php, 1636 | 1637 | which is no way to build an application - large or small. 1638 | 1639 | The other use for unit tests is contributing to open source. If you can write a 1640 | 1641 | test that shows broken functionality (i.e. fails), then fix it, and show the test 1642 | 1643 | passing, patches are much more likely to be accepted. If you run a project which 1644 | 1645 | accepts pull requests then you should suggest this as a requirement. 1646 | 1647 | PHPUnit is the de-facto testing framework for writing unit tests for PHP 1648 | 1649 | applications, but there are several alternatives 1650 | 1651 | • SimpleTest 1652 | 1653 | • Enhance PHP 1654 | 1655 | • PUnit 1656 | 1657 | • atoum 1658 | 1659 | Integration Testing 1660 | 1661 | From Wikipedia: 1662 | 1663 | Integration testing (sometimes called Integration and Testing, abbre- 1664 | 1665 | viated “I&T”) is the phase in software testing in which individual 1666 | 1667 | software modules are combined and tested as a group. It occurs 1668 | 1669 | after unit testing and before validation testing. Integration testing 1670 | 1671 | takes as its input modules that have been unit tested, groups them 1672 | 1673 | in larger aggregates, applies tests defined in an integration test plan 1674 | 1675 | to those aggregates, and delivers as its output the integrated system 1676 | 1677 | ready for system testing. 1678 | 1679 | Many of the same tools that can be used for unit testing can be used for 1680 | 1681 | integration testing as many of the same principles are used. 1682 | 1683 | 25 1684 | 1685 | Functional Testing 1686 | 1687 | Sometimes also known as acceptance testing, functional testing consists of using 1688 | 1689 | tools to create automated tests that actually use your application instead of just 1690 | 1691 | verifying that individual units of code are behaving correctly and that individual 1692 | 1693 | units can speak to each other correctly. These tools typically work using real 1694 | 1695 | data and simulating actual users of the application. 1696 | 1697 | Functional Testing Tools 1698 | 1699 | • Selenium 1700 | 1701 | • Mink 1702 | 1703 | • Codeception is a full-stack testing framework that includes acceptance testing tools 1704 | 1705 | Behavior Driven Development 1706 | 1707 | There are two different types of Behavior-Driven Development (BDD): SpecBDD 1708 | 1709 | and StoryBDD. SpecBDD focuses on technical behavior or code, while StoryBDD 1710 | 1711 | focuses on business or feature behaviors or interactions. PHP has frameworks 1712 | 1713 | for both types of BDD. 1714 | 1715 | With StoryBDD, you write human-readable stories that describe the behavior 1716 | 1717 | of your application. These stories can then be run as actual tests against your 1718 | 1719 | application. The framework used in PHP applications for StoryBDD is Behat, 1720 | 1721 | which is inspired by Ruby’s Cucumber project and implements the Gherkin DSL 1722 | 1723 | for describing feature behavior. 1724 | 1725 | With SpecBDD, you write specifications that describe how your actual code 1726 | 1727 | should behave. Instead of testing a function or method, you are describing how 1728 | 1729 | that function or method should behave. PHP offers the PHPSpec framework for 1730 | 1731 | this purpose. This framework is inspired by the RSpec project for Ruby. 1732 | 1733 | BDD Links 1734 | 1735 | • Behat, the StoryBDD framework for PHP, inspired by Ruby’s Cucumber 1736 | 1737 | project; 1738 | 1739 | • PHPSpec, the SpecBDD framework for PHP, inspired by Ruby’s RSpec 1740 | 1741 | project; 1742 | 1743 | • Codeception is a full-stack testing framework that uses BDD principles. 1744 | 1745 | 26 1746 | 1747 | Complementary Testing Tools 1748 | 1749 | Besides individual testing and behavior driven frameworks, there are also a 1750 | 1751 | number of generic frameworks and helper libraries useful for any preferred 1752 | 1753 | approach taken. 1754 | 1755 | Tool Links 1756 | 1757 | • Selenium is a browser automation tool which can be integrated with 1758 | 1759 | PHPUnit 1760 | 1761 | • Mockery is a Mock Object Framework which can be integrated with 1762 | 1763 | PHPUnit or PHPSpec 1764 | 1765 | • Prophecy is a highly opinionated yet very powerful and flexible PHP object mocking framework. It’s integrated with PHPSpec and can be used with 1766 | 1767 | PHPUnit. 1768 | 1769 | Back to Top 1770 | 1771 | Servers and Deployment 1772 | 1773 | PHP applications can be deployed and run on production web servers in a 1774 | 1775 | number of ways. 1776 | 1777 | Platform as a Service (PaaS) 1778 | 1779 | PaaS provides the system and network architecture necessary to run PHP 1780 | 1781 | applications on the web. This means little to no configuration for launching 1782 | 1783 | PHP applications or PHP frameworks. 1784 | 1785 | Recently PaaS has become a popular method for deploying, hosting, and scaling 1786 | 1787 | PHP applications of all sizes. You can find a list of PHP PaaS “Platform as a 1788 | 1789 | Service” providers in our resources section. 1790 | 1791 | Virtual or Dedicated Servers 1792 | 1793 | If you are comfortable with systems administration, or are interested in learning 1794 | 1795 | it, virtual or dedicated servers give you complete control of your application’s 1796 | 1797 | production environment. 1798 | 1799 | 27 1800 | 1801 | nginx and PHP-FPM 1802 | 1803 | PHP, via PHP’s built-in FastCGI Process Manager (FPM), pairs really nicely 1804 | 1805 | with nginx, which is a lightweight, high-performance web server. It uses less memory than Apache and can better handle more concurrent requests. This is 1806 | 1807 | especially important on virtual servers that don’t have much memory to spare. 1808 | 1809 | • Read more on nginx 1810 | 1811 | • Read more on PHP-FPM 1812 | 1813 | • Read more on setting up nginx and PHP-FPM securely 1814 | 1815 | Apache and PHP 1816 | 1817 | PHP and Apache have a long history together. Apache is wildly configurable and 1818 | 1819 | has many available modules to extend functionality. It is a popular choice for shared servers and an easy setup for PHP frameworks and open source apps like 1820 | 1821 | WordPress. Unfortunately, Apache uses more resources than nginx by default 1822 | 1823 | and cannot handle as many visitors at the same time. 1824 | 1825 | Apache has several possible configurations for running PHP. The most common 1826 | 1827 | and easiest to setup is the prefork MPM with mod_php5. While it isn’t the most memory efficient, it is the simplest to get working and to use. This is probably 1828 | 1829 | the best choice if you don’t want to dig too deeply into the server administration 1830 | 1831 | aspects. Note that if you use mod_php5 you MUST use the prefork MPM. 1832 | 1833 | Alternatively, if you want to squeeze more performance and stability out of 1834 | 1835 | Apache then you can take advantage of the same FPM system as nginx and 1836 | 1837 | run the worker MPM or event MPM with mod_fastcgi or mod_fcgid. This configuration will be significantly more memory efficient and much faster but it 1838 | 1839 | is more work to set up. 1840 | 1841 | • Read more on Apache 1842 | 1843 | • Read more on Multi-Processing Modules 1844 | 1845 | • Read more on mod_fastcgi 1846 | 1847 | • Read more on mod_fcgid 1848 | 1849 | Shared Servers 1850 | 1851 | PHP has shared servers to thank for its popularity. It is hard to find a host 1852 | 1853 | without PHP installed, but be sure it’s the latest version. Shared servers allow 1854 | 1855 | you and other developers to deploy websites to a single machine. The upside 1856 | 1857 | to this is that it has become a cheap commodity. The downside is that you 1858 | 1859 | never know what kind of a ruckus your neighboring tenants are going to create; 1860 | 1861 | loading down the server or opening up security holes are the main concerns. If 1862 | 1863 | your project’s budget can afford to avoid shared servers you should. 1864 | 1865 | 28 1866 | 1867 | Building and Deploying your Application 1868 | 1869 | If you find yourself doing manual database schema changes or running your 1870 | 1871 | tests manually before updating your files (manually), think twice! With every 1872 | 1873 | additional manual task needed to deploy a new version of your app, the chances 1874 | 1875 | for potentially fatal mistakes increase. Whether you’re dealing with a simple 1876 | 1877 | update, a comprehensive build process or even a continuous integration strategy, 1878 | 1879 | build automation is your friend. 1880 | 1881 | Among the tasks you might want to automate are: 1882 | 1883 | • Dependency management 1884 | 1885 | • Compilation, minification of your assets 1886 | 1887 | • Running tests 1888 | 1889 | • Creation of documentation 1890 | 1891 | • Packaging 1892 | 1893 | • Deployment 1894 | 1895 | Build Automation Tools 1896 | 1897 | Build tools can be described as a collection of scripts that handle common tasks 1898 | 1899 | of software deployment. The build tool is not a part of your software, it acts on 1900 | 1901 | your software from ‘outside’. 1902 | 1903 | There are many open source tools available to help you with build automation, 1904 | 1905 | some are written in PHP others aren’t. This shouldn’t hold you back from using 1906 | 1907 | them, if they’re better suited for the specific job. Here are a few examples: 1908 | 1909 | Phing is the easiest way to get started with automated deployment in the PHP 1910 | 1911 | world. With Phing you can control your packaging, deployment or testing process 1912 | 1913 | from within a simple XML build file. Phing (which is based on Apache Ant) 1914 | 1915 | provides a rich set of tasks usually needed to install or update a web app and 1916 | 1917 | can be extended with additional custom tasks, written in PHP. 1918 | 1919 | Capistrano is a system for intermediate-to-advanced programmers to execute commands in a structured, repeatable way on one or more remote machines. It 1920 | 1921 | is pre-configured for deploying Ruby on Rails applications, however people are 1922 | 1923 | successfully deploying PHP systems with it. Successful use of Capistrano 1924 | 1925 | depends on a working knowledge of Ruby and Rake. 1926 | 1927 | Dave Gardner’s blog post PHP Deployment with Capistrano is a good starting point for PHP developers interested in Capistrano. 1928 | 1929 | Chef is more than a deployment framework, it is a very powerful Ruby based system integration framework that doesn’t just deploy your app but can build 1930 | 1931 | your whole server environment or virtual boxes. 1932 | 1933 | Chef resources for PHP developers: 1934 | 1935 | 29 1936 | 1937 | • Three part blog series about deploying a LAMP application with Chef, 1938 | 1939 | Vagrant, and EC2 1940 | 1941 | • Chef Cookbook which installs and configures PHP 5.3 and the PEAR 1942 | 1943 | package management system 1944 | 1945 | Further reading: 1946 | 1947 | • Automate your project with Apache Ant 1948 | 1949 | • Maven, a build framework based on Ant and how to use it with PHP 1950 | 1951 | Continuous Integration 1952 | 1953 | Continuous Integration is a software development practice where 1954 | 1955 | members of a team integrate their work frequently, usually each 1956 | 1957 | person integrates at least daily — leading to multiple integrations 1958 | 1959 | per day. Many teams find that this approach leads to significantly 1960 | 1961 | reduced integration problems and allows a team to develop cohesive 1962 | 1963 | software more rapidly. 1964 | 1965 | – Martin Fowler 1966 | 1967 | There are different ways to implement continuous integration for PHP. Recently 1968 | 1969 | Travis CI has done a great job of making continuous integration a reality even for small projects. Travis CI is a hosted continuous integration service for the open 1970 | 1971 | source community. It is integrated with GitHub and offers first class support for 1972 | 1973 | many languages including PHP. 1974 | 1975 | Further reading: 1976 | 1977 | • Continuous Integration with Jenkins 1978 | 1979 | • Continuous Integration with PHPCI 1980 | 1981 | • Continuous Integration with Teamcity 1982 | 1983 | Back to Top 1984 | 1985 | Caching 1986 | 1987 | PHP is pretty quick by itself, but bottlenecks can arise when you make remote 1988 | 1989 | connections, load files, etc. Thankfully, there are various tools available to speed 1990 | 1991 | up certain parts of your application, or reduce the number of times these various 1992 | 1993 | time consuming tasks need to run. 1994 | 1995 | 30 1996 | 1997 | Bytecode Cache 1998 | 1999 | When a PHP file is executed, under the hood it is first compiled to bytecode 2000 | 2001 | (also known as opcode) and, only then, the bytecode is executed. If a PHP file 2002 | 2003 | is not modified, the bytecode will always be the same. This means that the 2004 | 2005 | compilation step is a waste of CPU resources. 2006 | 2007 | This is where Bytecode cache comes in. It prevents redundant compilation 2008 | 2009 | by storing bytecode in memory and reusing it on successive calls. Setting up 2010 | 2011 | bytecode cache is a matter of minutes, and your application will speed up 2012 | 2013 | significantly. There’s really no reason not to use it. 2014 | 2015 | Popular bytecodes caches are: 2016 | 2017 | • APC 2018 | 2019 | • XCache 2020 | 2021 | • Zend Optimizer+ (part of Zend Server package) 2022 | 2023 | • WinCache (extension for MS Windows Server) 2024 | 2025 | Object Caching 2026 | 2027 | There are times when it can be beneficial to cache individual objects in your 2028 | 2029 | code, such as with data that is expensive to get or database calls where the result 2030 | 2031 | is unlikely to change. You can use object caching software to hold these pieces 2032 | 2033 | of data in memory for extremely fast access later on. If you save these items to 2034 | 2035 | a data store after you retrieve them, then pull them directly from the cache for 2036 | 2037 | following requests, you can gain a significant improvement in performance as 2038 | 2039 | well as reduce the load on your database servers. 2040 | 2041 | Many of the popular bytecode caching solutions let you cache custom data as 2042 | 2043 | well, so there’s even more reason to take advantage of them. APC, XCache, and 2044 | 2045 | WinCache all provide APIs to save data from your PHP code to their memory 2046 | 2047 | cache. 2048 | 2049 | The most commonly used memory object caching systems are APC and mem- 2050 | 2051 | cached. APC is an excellent choice for object caching, it includes a simple API 2052 | 2053 | for adding your own data to its memory cache and is very easy to setup and 2054 | 2055 | use. The one real limitation of APC is that it is tied to the server it’s installed 2056 | 2057 | on. Memcached on the other hand is installed as a separate service and can be 2058 | 2059 | accessed across the network, meaning that you can store objects in a hyper-fast 2060 | 2061 | data store in a central location and many different systems can pull from it. 2062 | 2063 | Note that when running PHP as a (Fast-)CGI application inside your webserver, 2064 | 2065 | every PHP process will have its own cache, i.e. APC data is not shared be- 2066 | 2067 | tween your worker processes. In these cases, you might want to consider using 2068 | 2069 | memcached instead, as it’s not tied to the PHP processes. 2070 | 2071 | 31 2072 | 2073 | In a networked configuration APC will usually outperform memcached in terms 2074 | 2075 | of access speed, but memcached will be able to scale up faster and further. If 2076 | 2077 | you do not expect to have multiple servers running your application, or do not 2078 | 2079 | need the extra features that memcached offers then APC is probably your best 2080 | 2081 | choice for object caching. 2082 | 2083 | Example logic using APC: 2084 | 2085 | . 13 | 14 | You need to have Jekyll, pandoc, MacTex (or at least pdflatex for PDF output) 15 | 16 | ## NOTICE 17 | 18 | This currently only outputs in PDF format. You may choose to skip this mess and 19 | download the PDF or single HTML version of the site also included right here. 20 | 21 | The PDF conversion required MacTex.pkg which was 2.3 GB and 4.33 GB decompressed. 22 | 23 | If you need an updated version of the PDF without going through the hassle of setting 24 | anything up, just send me a message and I will regenerate the PDF. 25 | 26 | **Even better, send me a cronjob that updates the PDF nightly** 27 | 28 | *Thanks! -Isam Machlovi* 29 | -------------------------------------------------------------------------------- /build-pdf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This uses pandoc to convert PHP-The-Right-Way to a PDF. 3 | # github.com/lsd for this + generated PDFs / ePubs / Mobi / etc. 4 | 5 | echo "----------------\n" 6 | echo "Make sure you are in the root file of the SOURCE of the site." 7 | echo "Make sure pandoc and jekyll are installed" 8 | echo "For example, ..." 9 | echo "$ git clone https://github.com/codeguy/php-the-right-way.git" 10 | echo "$ cd php-the-right-way/" 11 | echo "$ cat CNAME" 12 | echo "$ sh build-html-to-pdf.sh" 13 | echo "----------------\n" 14 | 15 | echo "Starting Jekyll build and then serving. OK? (any key or ctrl+c to quit)" 16 | read 17 | 18 | jekyll build 19 | jekyll serve 20 | 21 | echo "Assuming site is on localhost:4000. Now running pandoc to generate single HTML." 22 | echo "this: pandoc -s -S --toc -c styles/all.css http://localhost:4000 -o php-the-right-way-single-html.html" 23 | echo "... OK?" 24 | read 25 | pandoc -s -S --toc -c styles/all.css http://localhost:4000 -o php-the-right-way-single-html.html 26 | 27 | echo "Edit the outputted HTML file." 28 | echo "Save it and then hit any key to continue." 29 | echo "(CTRL+C to terminate at any time)" 30 | read 31 | 32 | echo "Finished? Use this step to remove unwanted things or fix formatting in the HTML" 33 | echo "Examples of issues: " 34 | echo "* There are 2 ToC (remove --toc flag above or manually remove the HTML for one of the ToC)" 35 | echo "* I added to my copy" 36 | echo "* I added to my copy" 37 | echo "* I removed some pages I don't need (contribute, disclaimer, etc.." 38 | echo "Anyway, last warning before making PDF. Proceed? (CTRL+C to die)" 39 | read 40 | 41 | 42 | -------------------------------------------------------------------------------- /php-the-right-way-06-21-2013.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsd/php-the-right-way-pdf/fdf3c121eea1d71ff167cd88a8729281a643932e/php-the-right-way-06-21-2013.pdf -------------------------------------------------------------------------------- /php-the-right-way-06212013.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |There’s a lot of outdated information on the Web that leads new PHP users astray, propagating bad practices and bad code. This must stop. PHP: The Right Way is an easy-to-read, quick reference for PHP best practices, accepted coding standards, and links to authoritative tutorials around the Web.
130 | 131 |If you are just getting started with PHP make sure to start with the current stable release of PHP 5.4. PHP has made great strides adding powerful new features over the last few years. Don’t let the minor version number difference between 5.2 and 5.4 fool you, it represents major improvements. If you are looking for a function or it’s usage, the documentation on the php.net website will have the answer.
134 |You can start learning PHP without the hassle of installing and configuring a full-fledged web server (PHP 5.4 required). To start the server, run the following from your terminal in your project’s web root:
136 |> php -S localhost:8000
137 |
140 | OSX comes prepackaged with PHP but it is normally a little behind the latest stable. Lion comes with PHP 5.3.6 and Mountain Lion has 5.3.10.
142 |To update PHP on OSX you can get it installed through a number of Mac package managers, with php-osx by Liip being recommended.
143 |The other option is to compile it yourself, in that case be sure to have installed either Xcode or Apple’s substitute “Command Line Tools for Xcode” downloadable from Apple’s Mac Developer Center.
144 |For a complete “all-in-one” package including PHP, Apache web server and MySQL database, all this with a nice control GUI, try MAMP.
145 |PHP is available in several ways for Windows. You can download the binaries and until recently you could use a ‘.msi’ installer. The installer is no longer supported and stops at PHP 5.3.0.
147 |For learning and local development you can use the built in webserver with PHP 5.4 so you don’t need to worry about configuring it. If you would like an “all-in-one” which includes a full-blown webserver and MySQL too then tools such as the Web Platform Installer, Zend Server CE, XAMPP and WAMP will help get a Windows development environment up and running fast. That said, these tools will be a little different from production so be careful of environment differences if you are working on Windows and deploying to Linux.
148 |If you need to run your production system on Windows then IIS7 will give you the most stable and best performance. You can use phpmanager (a GUI plugin for IIS7) to make configuring and managing PHP simple. IIS7 comes with FastCGI built in and ready to go, you just need to configure PHP as a handler. For support and additional resources there is a dedicated area on iis.net for PHP.
149 |Running your application on different environments in development and production can lead to strange bugs popping up when you go live. It’s also tricky to keep different development environments up to date with the same version for all libraries used when working with a team of developers.
151 |If you are developing on Windows and deploying to Linux (or anything non-Windows) or are developing in a team, you should consider using a virtual machine. This sounds tricky, but using Vagrant you can set up a simple virtual machine with only a few steps. These base boxes can then be set up manually, or you can use “provisioning” software such as Puppet or Chef to do this for you. Provisioning the base box is a great way to ensure that multiple boxes are set up in an identical fashion and removes the need for you to maintain complicated “set up” command lists. You can also “destroy” your base box and recreate it without many manual steps, making it easy to create a “fresh” installation.
152 |Vagrant creates shared folders used to share your code between your host and your virtual machine, meaning you can create and edit your files on your host machine and then run the code inside your virtual machine.
153 | 154 |The PHP community is large and diverse, composed of innumerable libraries, frameworks, and components. It is common for PHP developers to choose several of these and combine them into a single project. It is important that PHP code adhere (as close as possible) to a common code style to make it easy for developers to mix and match various libraries for their projects.
156 |The Framework Interop Group has proposed and approved a series of style recommendations, known as PSR-0, PSR-1 and PSR-2. Don’t let the funny names confuse you, these recommendations are merely a set of rules that some projects like Drupal, Zend, Symfony, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium, etc are starting to adopt. You can use them for your own projects, or continue to use your own personal style.
157 |Ideally you should write PHP code that adheres to a known standard. This could be any combination of PSR’s, or one of the coding standards made by PEAR or Zend. This means other developers can easily read and work with your code, and applications that implement the components can have consistency even when working with lots of third-party code.
158 |You can use PHP_CodeSniffer to check code against any one of these recommendations, and plugins for text editors like Sublime Text 2 to be given real time feedback.
166 |Use Fabien Potencier’s PHP Coding Standards Fixer to automatically modify your code syntax so that it conforms with these standards, saving you from fixing each problem by hand.
167 |English is preferred for all symbol names and code infrastructure. Comments may be written in any language easily readable by all current and future parties who may be working on the codebase.
168 | 169 |PHP is a flexible, dynamic language that supports a variety of programming techniques. It has evolved dramatically over the years, notably adding a solid object-oriented model in PHP 5.0 (2004), anonymous functions and namespaces in PHP 5.3 (2009), and traits in PHP 5.4 (2012).
172 |PHP has a very complete set of object-oriented programming features including support for classes, abstract classes, interfaces, inheritance, constructors, cloning, exceptions, and more.
174 |PHP supports first-class function, meaning that a function can be assigned to a variable. Both user defined and built-in functions can be referenced by a variable and invoked dynamically. Functions can be passed as arguments to other functions (feature called Higher-order functions) and function can return other functions.
180 |Recursion, a feature that allows a function to call itself is supported by the language, but most of the PHP code focus on iteration.
181 |New anonymous functions (with support for closures) are present since PHP 5.3 (2009).
182 |PHP 5.4 added the ability to bind closures to an object’s scope and also improved support for callables such that they can be used interchangeably with anonymous functions in almost all cases.
183 |call_user_func_array
PHP supports various forms of meta programming through mechanisms like the Reflection API and Magic Methods. There are many Magic Methods available like __get()
, __set()
, __clone()
, __toString()
, __invoke()
, etc. that allow developers to hook into class behavior. Ruby developers often say that PHP is lacking method_missing
, but it is available as __call()
and __callStatic()
.
As mentioned above, the PHP community has a lot of developers creating lots of code. This means that one library’s PHP code may use the same class name as another library. When both libraries are used in the same namespace, they collide and cause trouble.
199 |Namespaces solve this problem. As described in the PHP reference manual, namespaces may be compared to operating system directories that namespace files; two files with the same name may co-exist in separate directories. Likewise, two PHP classes with the same name may co-exist in separate PHP namespaces. It’s as simple as that.
200 |It is important for you to namespace your code so that it may be used by other developers without fear of colliding with other libraries.
201 |One recommended way to use namespaces is outlined in PSR-0, which aims to provide a standard file, class and namespace convention to allow plug-and-play code.
202 |The Standard PHP Library (SPL) is packaged with PHP and provides a collection of classes and interfaces. It is made up primarily of commonly needed datastructure classes (stack, queue, heap, and so on), and iterators which can traverse over these datastructures or your own classes which implement SPL interfaces.
208 |PHP was created primarily to write web applications, but it’s also useful for scripting command line interface (CLI) programs. Command line PHP programs can help you automate common tasks like testing, deployment, and application administrativia.
213 |CLI PHP programs are powerful because you can use your app’s code directly without having to create and secure a web GUI for it. Just be sure not to put your CLI PHP scripts in your public web root!
214 |Try running PHP from your command line:
215 |> php -i
216 | The -i
option will print your PHP configuration just like the phpinfo
function.
The -a
option provides an interactive shell, similar to ruby’s IRB or python’s interactive shell. There are a number of other useful command line options, too.
Let’s write a simple “Hello, $name” CLI program. To try it out, create a file named hello.php
, as below.
<?php
220 | if ($argc != 2) {
221 | echo "Usage: php hello.php [name].\n";
222 | exit(1);
223 | }
224 | $name = $argv[1];
225 | echo "Hello, $name\n";
226 | PHP sets up two special variables based on the arguments your script is run with. $argc
is an integer variable containing the argument count and $argv
is an array variable containing each argument’s value. The first argument is always the name of your PHP script file, in this case hello.php
.
The exit()
expression is used with a non zero number to let the shell know that the command failed. Commonly used exit codes can be found here
To run our script, above, from the command line:
229 |> php hello.php
230 | Usage: php hello.php [name]
231 | > php hello.php world
232 | Hello, world
233 | One of the most useful tools in software development is a proper debugger. It allows you to trace the execution of your code and monitor the contents of the stack. XDebug, PHP’s debugger, can be utilized by various IDEs to provide Breakpoints and stack inspection. It can also allow tools like PHPUnit and KCacheGrind to perform code coverage analysis and code profiling.
239 |If you find yourself in a bind, willing to resort to var_dump/print_r, and you still can’t find the solution - maybe you need to use the debugger.
240 |Installing XDebug can be tricky, but one of its most important features is “Remote Debugging” - if you develop code locally and then test it inside a VM or on another server, Remote Debugging is the feature that you will want to enable right away.
241 |Traditionally, you will modify your Apache VHost or .htaccess file with these values:
242 |php_value xdebug.remote_host=192.168.?.?
243 | php_value xdebug.remote_port=9000
244 | The “remote host” and “remote port” will correspond to your local computer and the port that you configure your IDE to listen on. Then it’s just a matter of putting your IDE into “listen for connections” mode, and loading the URL:
245 |http://your-website.example.com/index.php?XDEBUG_SESSION_START=1
246 | Your IDE will now intercept the current state as the script executes, allowing you to set breakpoints and probe the values in memory.
247 |There are a ton of PHP libraries, frameworks, and components to choose from. Your project will likely use several of them — these are project dependencies. Until recently, PHP did not have a good way to manage these project dependencies. Even if you managed them manually, you still had to worry about autoloaders. No more.
253 |Currently there are two major package management systems for PHP - Composer and PEAR. Which one is right for you? The answer is both.
254 |In general, Composer packages will be available only in the projects that you explicitly specify whereas a PEAR package would be available to all of your PHP projects. While PEAR might sound like the easier approach at first glance, there are advantages to using a project-by-project approach to your dependencies.
259 |Composer is a brilliant dependency manager for PHP. List your project’s dependencies in a composer.json
file and, with a few simple commands, Composer will automatically download your project’s dependencies and setup autoloading for you.
There are already a lot of PHP libraries that are compatible with Composer, ready to be used in your project. These “packages” are listed on Packagist, the official repository for Composer-compatible PHP libraries.
262 |You can install Composer locally (in your current working directory; though this is no longer recommended) or globally (e.g. /usr/local/bin). Let’s assume you want to install Composer locally. From your project’s root directory:
264 |curl -s https://getcomposer.org/installer | php
265 | This will download composer.phar
(a PHP binary archive). You can run this with php
to manage your project dependencies. Please Note: If you pipe downloaded code directly into an interpreter, please read the code online first to confirm it is safe.
Manually installing Composer is an advanced technique; however, there are various reasons why a developer might prefer this method vs. using the interactive installation routine. The interactive installation checks your PHP installation to ensure that:
268 |.phar
files can be executed correctlyphp.ini
settings are setSince a manual installation performs none of these checks, you have to decide whether the trade-off is worth it for you. As such, below is how to obtain Composer manually:
276 |curl -s https://getcomposer.org/composer.phar -o $HOME/local/bin/composer
277 | chmod +x $HOME/local/bin/composer
278 | The path $HOME/local/bin
(or a directory of your choice) should be in your $PATH
environment variable. This will result in a composer
command being available.
When you come across documentation that states to run Composer as php composer.phar install
, you can substitute that with:
composer install
281 | Composer keeps track of your project’s dependencies in a file called composer.json
. You can manage it by hand if you like, or use Composer itself. The php composer.phar require
command adds a project dependency and if you don’t have a composer.json
file, one will be created. Here’s an example that adds Twig as a dependency of your project. Run it in your project’s root directory where you’ve downloaded composer.phar
:
php composer.phar require twig/twig:~1.8
284 | Alternatively the php composer.phar init
command will guide you through creating a full composer.json
file for your project. Either way, once you’ve created your composer.json
file you can tell Composer to download and install your dependencies into the vendors/
directory. This also applies to projects you’ve downloaded that already provide a composer.json
file:
php composer.phar install
286 | Next, add this line to your application’s primary PHP file; this will tell PHP to use Composer’s autoloader for your project dependencies.
287 |<?php
288 | require 'vendor/autoload.php';
289 | Now you can use your project dependencies, and they’ll be autoloaded on demand.
290 |Composer creates a file called composer.lock
which stores the exact version of each package it downloaded when you first ran php composer.phar install
. If you share your project with other coders and the composer.lock
file is part of your distribution, when they run php composer.phar install
they’ll get the same versions as you. To update your dependencies, run php composer.phar update
.
This is most useful when you define your version requirements flexibly. For instance a version requirement of ~1.8 means “anything newer than 1.8.0, but less than 2.0.x-dev”. You can also use the *
wildcard as in 1.8.*
. Now Composer’s php composer.phar update
command will upgrade all your dependencies to the newest version that fits the restrictions you define.
The Security Advisories Checker is a web service and a command-line tool, both will examine your composer.lock
file and tell you if you need to update any of your dependencies.
Another veteran package manager that many PHP developers enjoy is PEAR. It behaves much the same way as Composer, but has some noteable differences.
300 |PEAR requires each package to have a specific structure, which means that the author of the package must prepare it for usage with PEAR. Using a project which was not prepared to work with PEAR is not possible.
301 |PEAR installs packages globally, which means after installing them once they are available to all projects on that server. This can be good if many projects rely on the same package with the same version but might lead to problems if version conflicts between two projects arise.
302 |You can install PEAR by downloading the phar installer and executing it. The PEAR documentation has detailed install instructions for every operating system.
304 |If you are using Linux, you can also have a look at your distribution package manager. Debian and Ubuntu for example have a apt php-pear
package.
If the package is listed on the PEAR packages list, you can install it by specifying the official name:
307 |pear install foo
308 | If the package is hosted on another channel, you need to discover
the channel first and also specify it when installing. See the Using channel docs for more information on this topic.
If you are already using Composer and you would like to install some PEAR code too, you can use Composer to handle your PEAR dependencies. This example will install code from pear2.php.net
:
{
315 | "repositories": [
316 | {
317 | "type": "pear",
318 | "url": "http://pear2.php.net"
319 | }
320 | ],
321 | "require": {
322 | "pear-pear2/PEAR2_Text_Markdown": "*",
323 | "pear-pear2/PEAR2_HTTP_Request": "*"
324 | }
325 | }
326 | The first section "repositories"
will be used to let Composer know it should “initialise” (or “discover” in PEAR terminology) the pear repo. Then the require section will prefix the package name like this:
328 |330 |pear-channel/Package
329 |
The “pear” prefix is hardcoded to avoid any conflicts, as a pear channel could be the same as another packages vendor name for example, then the channel short name (or full URL) can be used to reference which channel the package is in.
331 |When this code is installed it will be available in your vendor directory and automatically available through the Composer autoloader:
332 |333 |335 |vendor/pear-pear2.php.net/PEAR2_HTTP_Request/pear2/HTTP/Request.php
334 |
To use this PEAR package simply reference it like so:
336 |$request = new pear2\HTTP\Request();
337 | PHP is a vast language that allows coders of all levels the ability to produce code not only quickly, but efficiently. However while advancing through the language, we often forget the basics that we first learnt (or overlooked) in favor of short cuts and/or bad habits. To help combat this common issue, this section is aimed at reminding coders of the basic coding practices within PHP.
344 |PHP has a class named DateTime to help you when reading, writing, comparing or calculating with date and time. There are many date and time related functions in PHP besides DateTime, but it provides nice object-oriented interface to most common uses. It can handle time zones, but that is outside this short introduction.
349 |To start working with DateTime, convert raw date and time string to an object with createFromFormat()
factory method or do new \DateTime
to get the current date and time. Use format()
method to convert DateTime back to a string for output.
<?php
351 | $raw = '22. 11. 1968';
352 | $start = \DateTime::createFromFormat('d. m. Y', $raw);
353 |
354 | echo 'Start date: ' . $start->format('m/d/Y') . "\n";
355 | Calculating with DateTime is possible with the DateInterval class. DateTime has methods like add()
and sub()
that take a DateInterval as an argument. Do not write code that expect same number of seconds in every day, both daylight saving and timezone alterations will break that assumption. Use date intervals instead. To calculate date difference use the diff()
method. It will return new DateInterval, which is super easy to display.
<?php
357 | // create a copy of $start and add one month and 6 days
358 | $end = clone $start;
359 | $end->add(new \DateInterval('P1M6D'));
360 |
361 | $diff = $end->diff($start);
362 | echo 'Difference: ' . $diff->format('%m month, %d days (total: %a days)') . "\n";
363 | // Difference: 1 month, 6 days (total: 37 days)
364 | On DateTime objects you can use standard comparison:
365 |<?php
366 | if ($start < $end) {
367 | echo "Start is before end!\n";
368 | }
369 | One last example to demonstrate the DatePeriod class. It is used to iterate over recurring events. It can take two DateTime objects, start and end, and the interval for which it will return all events in between.
370 |<?php
371 | // output all thursdays between $start and $end
372 | $periodInterval = \DateInterval::createFromDateString('first thursday');
373 | $periodIterator = new \DatePeriod($start, $periodInterval, $end, \DatePeriod::EXCLUDE_START_DATE);
374 | foreach ($periodIterator as $date) {
375 | // output each date in the period
376 | echo $date->format('m/d/Y') . ' ';
377 | }
378 | When you are building your application it is helpful to use common patterns in your code and common patterns for the overall structure of your project. Using common patterns is helpful because it makes it much easier to manage your code and lets other developers quickly understand how everything fits together.
384 |If you use a framework then most of the higher level code and project structure will be based on that framework, so a lot of the pattern decisions are made for you. But it is still up to you to pick out the best patterns to follow in the code you build on top of the framework. If, on the other hand, you are not using a framework to build your application then you have to find the patterns that best suit the type and size of application that you’re building.
385 |Exceptions are a standard part of most popular programming languages, but they are often overlooked by PHP programmers. Languages like Ruby are extremely Exception heavy, so whenever something goes wrong such as a HTTP request failing, or a DB query goes wrong, or even if an image asset could not be found, Ruby (or the gems being used) will throw an exception to the screen meaning you instantly know there is a mistake.
390 |PHP itself is fairly lax with this, and a call to file_get_contents()
will usually just get you a FALSE
and a warning. Many older PHP frameworks like CodeIgniter will just return a false, log a message to their proprietary logs and maybe let you use a method like $this->upload->get_error()
to see what went wrong. The problem here is that you have to go looking for a mistake and check the docs to see what the error method is for this class, instead of having it made extremely obvious.
Another problem is when classes automatically throw an error to the screen and exit the process. When you do this you stop another developer from being able to dynamically handle that error. Exceptions should be thrown to make a developer aware of an error, then they can choose how to handle this. E.g:
392 |<?php
393 | $email = new Fuel\Email;
394 | $email->subject('My Subject');
395 | $email->body('How the heck are you?');
396 | $email->to('guy@example.com', 'Some Guy');
397 |
398 | try
399 | {
400 | $email->send();
401 | }
402 | catch(Fuel\Email\ValidationFailedException $e)
403 | {
404 | // The validation failed
405 | }
406 | catch(Fuel\Email\SendingFailedException $e)
407 | {
408 | // The driver could not send the email
409 | }
410 | The generic Exception
class provides very little debugging context for the developer; however, to remedy this, it is possible to create a specialized Exception
type by sub-classing the generic Exception
class:
<?php
413 | class ValidationException extends Exception {}
414 | This means you can add multiple catch blocks and handle different Exceptions differently. This can lead to the creation of a lot of custom Exceptions, some of which could have been avoided using the SPL Exceptions provided in the SPL extension.
415 |If for example you use the __call()
Magic Method and an invalid method is requested then instead of throwing a standard Exception which is vague, or creating a custom Exception just for that, you could just throw new BadFunctionCallException;
.
Many times your PHP code will use a database to persist information. You have a few options to connect and interact with your database. The recommended option until PHP 5.1.0 was to use native drivers such as mysql, mysqli, pgsql, etc.
425 |Native drivers are great if you are only using ONE database in your application, but if, for example, you are using MySQL and a little bit of MSSQL, or you need to connect to an Oracle database, then you will not be able to use the same drivers. You’ll need to learn a brand new API for each database — and that can get silly.
426 |As an extra note on native drivers, the mysql extension for PHP is no longer in active development, and the official status since PHP 5.4.0 is “Long term deprecation”. This means it will be removed within the next few releases, so by PHP 5.6 (or whatever comes after 5.5) it may well be gone. If you are using mysql_connect()
and mysql_query()
in your applications then you will be faced with a rewrite at some point down the line, so the best option is to replace mysql usage with mysqli or PDO in your applications within your own development schedules so you won’t be rushed later on. If you are starting from scratch then absolutely do not use the mysql extension: use the MySQLi extension, or use PDO.
PDO is a database connection abstraction library — built into PHP since 5.1.0 — that provides a common interface to talk with many different databases. PDO will not translate your SQL queries or emulate missing features; it is purely for connecting to multiple types of database with the same API.
432 |More importantly, PDO
allows you to safely inject foreign input (e.g. IDs) into your SQL queries without worrying about database SQL injection attacks. This is possible using PDO statements and bound parameters.
Let’s assume a PHP script receives a numeric ID as a query parameter. This ID should be used to fetch a user record from a database. This is the wrong
way to do this:
<?php
435 | $pdo = new PDO('sqlite:users.db');
436 | $pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!
437 | This is terrible code. You are inserting a raw query parameter into a SQL query. This will get you hacked in a heartbeat. Just imagine if a hacker passes in an inventive id
parameter by calling a URL like http://domain.com/?id=1%3BDELETE+FROM+users
. This will set the $_GET['id']
variable to 1;DELETE FROM users
which will delete all of your users! Instead, you should sanitize the ID input using PDO bound parameters.
<?php
439 | $pdo = new PDO('sqlite:users.db');
440 | $stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
441 | $stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); //<-- Automatically sanitized by PDO
442 | $stmt->execute();
443 | This is correct code. It uses a bound parameter on a PDO statement. This escapes the foreign input ID before it is introduced to the database preventing potential SQL injection attacks.
444 |You should also be aware that database connections use up resources and it was not unheard-of to have resources exhausted if connections were not implicitly closed, however this was more common in other languages. Using PDO you can implicitly close the connection by destroying the object by ensuring all remaining references to it are deleted, ie. set to NULL. If you don’t do this explicitly, PHP will automatically close the connection when your script ends unless of course you are using persistent connections.
448 |Many frameworks provide their own abstraction layer which may or may not sit on top of PDO. These will often emulate features for one database system that another is missing from another by wrapping your queries in PHP methods, giving you actual database abstraction. This will of course add a little overhead, but if you are building a portable application that needs to work with MySQL, PostgreSQL and SQLite then a little overhead will be worth it the sake of code cleanliness.
453 |Some abstraction layers have been built using the PSR-0 namespace standard so can be installed in any application you like:
454 |There are bad people ready and willing to exploit your web application. It is important that you take necessary precautions to harden your web application’s security. Luckily, the fine folks at The Open Web Application Security Project (OWASP) have compiled a comprehensive list of known security issues and methods to protect yourself against them. This is a must read for the security-conscious developer.
464 |Eventually everyone builds a PHP application that relies on user login. Usernames and passwords are stored in a database and later used to authenticate users upon login.
469 |It is important that you properly hash passwords before storing them. Password hashing is an irreversible, one way function performed against the users password. This produces a fixed-length string that can not be feasibly reversed. This means you can compare a hash against another to determine if they both came from the same source string, but you can not determine the original string. If passwords are not hashed and your database is accessed by an unauthorized third-party, all user accounts are now compromised. Some users may (unfortunately) use the same password for other services. Therefore, it is important to take security seriously.
470 |Hashing passwords with password_hash
In PHP 5.5 password_hash
will be introduced. At this time it is using BCrypt, the strongest algorithm currently supported by PHP. It will be updated in the future to support more algorithms as needed though. The password_compat
library was created to provide forward compatibility for PHP >= 5.3.7.
Below we hash a string, we then check the hash against a new string. Because our two source strings are different (‘secret-password’ vs. ‘bad-password’) this login will fail.
473 |
474 | <?php
475 | require 'password.php';
476 |
477 | $passwordHash = password_hash('secret-password', PASSWORD_DEFAULT);
478 |
479 | if (password_verify('bad-password', $passwordHash)) {
480 | //Correct Password
481 | } else {
482 | //Wrong password
483 | }
484 | password_hash
password_compat
for PHP >= 5.3.7 && < 5.5password_hash
RFCNever ever (ever) trust foreign input introduced to your PHP code. Always sanitize and validate foreign input before using it in code. The filter_var
and filter_input
functions can sanitize text and validate text formats (e.g. email addresses).
Foreign input can be anything: $_GET
and $_POST
form input data, some values in the $_SERVER
superglobal, and the HTTP request body via fopen('php://input', 'r')
. Remember, foreign input is not limited to form data submitted by the user. Uploaded and downloaded files, session values, cookie data, and data from third-party web services are foreign input, too.
While foreign data can be stored, combined, and accessed later, it is still foreign input. Every time you process, output, concatenate, or include data in your code, ask yourself if the data is filtered properly and can it be trusted.
494 |Data may be filtered differently based on its purpose. For example, when unfiltered foreign input is passed into HTML page output, it can execute HTML and JavaScript on your site! This is known as Cross-Site Scripting (XSS) and can be a very dangerous attack. One way to avoid XSS is to sanitize all user-generated data before outputting it to your page by removing HTML tags with the strip_tags
function or escaping characters with special meaning into their respective HTML entities with the htmlentities
or htmlspecialchars
functions.
Another example is passing options to be executed on the command line. This can be extremely dangerous (and is usually a bad idea), but you can use the built-in escapeshellarg
function to sanitize the executed command’s arguments.
One last example is accepting foreign input to determine a file to load from the filesystem. This can be exploited by changing the filename to a file path. You need to remove ”/”, “../”, null bytes, or other characters from the file path so it can’t load hidden, non-public, or sensitive files.
497 |filter_var
filter_input
Sanitization removes (or escapes) illegal or unsafe characters from foreign input.
505 |For example, you should sanitize foreign input before including the input in HTML or inserting it into a raw SQL query. When you use bound parameters with PDO, it will sanitize the input for you.
506 |Sometimes it is required to allow some safe HTML tags in the input when including it in the HTML page. This is very hard to do and many avoid it by using other more restricted formatting like Markdown or BBCode, although whitelisting libraries like HTML Purifier exists for this reason.
507 | 508 |Validation ensures that foreign input is what you expect. For example, you may want to validate an email address, a phone number, or age when processing a registration submission.
510 | 511 |When creating configuration files for your applications, best practices recommend that one of the following methods be followed:
513 |.php
extension. This ensures that, even if the script is accessed directly, it will not be outputed as plain text.NOTE: As of PHP 5.4.0 the register_globals
setting has been removed and can no longer be used. This is only included as a warning for anyone in the process of upgrading a legacy application.
When enabled, the register_globals
configuration setting that makes several types of variables (including ones from $_POST
, $_GET
and $_REQUEST
) available in the global scope of your application. This can easily lead to security issues as your application cannot effectively tell where the data is coming from.
For example: $_GET['foo']
would be available via $foo
, which can override variables that have not been declared. If you are using PHP < 5.4.0 make sure that register_globals
is off.
Error logging can be useful in finding the problem spots in your application, but it can also expose information about the structure of your application to the outside world. To effectively protect your application from issues that could be caused by the output of these messages, you need to configure your server differently in development versus production (live).
527 |To show every possible error during development, configure the following settings in your php.ini
:
display_errors = On
530 | display_startup_errors = On
531 | error_reporting = -1
532 | log_errors = On
533 | 534 |536 |Passing in the value
535 |-1
will show every possible error, even when new levels and constants are added in future PHP versions. TheE_ALL
constant also behaves this way as of PHP 5.4. - php.net
The E_STRICT
error level constant was introduced in 5.3.0 and is not part of E_ALL
, however it became part of E_ALL
in 5.4.0. What does this mean? In terms of reporting every possible error in version 5.3 it means you must use either -1
or E_ALL | E_STRICT
.
Reporting every possible error by PHP version
538 |-1
or E_ALL
-1
or E_ALL | E_STRICT
-1
or E_ALL
To hide errors on your production environment, configure your php.ini
as:
display_errors = Off
546 | display_startup_errors = Off
547 | error_reporting = E_ALL
548 | log_errors = On
549 | With these settings in production, errors will still be logged to the error logs for the web server, but will not be shown to the user. For more information on these settings, see the PHP manual:
550 |Writing automated tests for your PHP code is considered a best practice and can lead to well-built applications. Automated tests are a great tool for making sure your application does not break when you are making changes or adding new functionality and should not be ignored.
559 |There are several different types of testing tools (or frameworks) available for PHP, which use different approaches - all of which are trying to avoid manual testing and the need for large Quality Assurance teams, just to make sure recent changes didn’t break existing functionality.
560 |From Wikipedia:
562 |563 |565 |Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: first the developer writes a failing automated test case that defines a desired improvement or new function, then produces code to pass that test and finally refactors the new code to acceptable standards. Kent Beck, who is credited with having developed or ‘rediscovered’ the technique, stated in 2003 that TDD encourages simple designs and inspires confidence
564 |
There are several different types of testing that you can do for your application
566 |Unit Testing is a programming approach to ensure functions, classes and methods are working as expected, from the point you build them all the way through the development cycle. By checking values going in and out of various functions and methods, you can make sure the internal logic is working correctly. By using Dependency Injection and building “mock” classes and stubs you can verify that dependencies are correctly used for even better test coverage.
568 |When you create a class or function you should create a unit test for each behavior it must have. At a very basic level you should make sure it errors if you send it bad arguments and make sure it works if you send it valid arguments. This will help ensure that when you make changes to this class or function later on in the development cycle that the old functionality continues to work as expected. The only alternative to this would be var_dump() in a test.php, which is no way to build an application - large or small.
569 |The other use for unit tests is contributing to open source. If you can write a test that shows broken functionality (i.e. fails), then fix it, and show the test passing, patches are much more likely to be accepted. If you run a project which accepts pull requests then you should suggest this as a requirement.
570 |PHPUnit is the de-facto testing framework for writing unit tests for PHP applications, but there are several alternatives
571 |From Wikipedia:
579 |580 |582 |Integration testing (sometimes called Integration and Testing, abbreviated “I&T”) is the phase in software testing in which individual software modules are combined and tested as a group. It occurs after unit testing and before validation testing. Integration testing takes as its input modules that have been unit tested, groups them in larger aggregates, applies tests defined in an integration test plan to those aggregates, and delivers as its output the integrated system ready for system testing.
581 |
Many of the same tools that can be used for unit testing can be used for integration testing as many of the same principles are used.
583 |Sometimes also known as acceptance testing, functional testing consists of using tools to create automated tests that actually use your application instead of just verifying that individual units of code are behaving correctly and that individual units can speak to each other correctly. These tools typically work using real data and simulating actual users of the application.
585 |There are two different types of Behavior-Driven Development (BDD): SpecBDD and StoryBDD. SpecBDD focuses on technical behavior or code, while StoryBDD focuses on business or feature behaviors or interactions. PHP has frameworks for both types of BDD.
593 |With StoryBDD, you write human-readable stories that describe the behavior of your application. These stories can then be run as actual tests against your application. The framework used in PHP applications for StoryBDD is Behat, which is inspired by Ruby’s Cucumber project and implements the Gherkin DSL for describing feature behavior.
594 |With SpecBDD, you write specifications that describe how your actual code should behave. Instead of testing a function or method, you are describing how that function or method should behave. PHP offers the PHPSpec framework for this purpose. This framework is inspired by the RSpec project for Ruby.
595 |Besides individual testing and behavior driven frameworks, there are also a number of generic frameworks and helper libraries useful for any preferred approach taken.
603 |PHP applications can be deployed and run on production web servers in a number of ways.
612 |PaaS provides the system and network architecture necessary to run PHP applications on the web. This means little to no configuration for launching PHP applications or PHP frameworks.
614 |Recently PaaS has become a popular method for deploying, hosting, and scaling PHP applications of all sizes. You can find a list of PHP PaaS “Platform as a Service” providers in our resources section.
615 |If you are comfortable with systems administration, or are interested in learning it, virtual or dedicated servers give you complete control of your application’s production environment.
617 |PHP, via PHP’s built-in FastCGI Process Manager (FPM), pairs really nicely with nginx, which is a lightweight, high-performance web server. It uses less memory than Apache and can better handle more concurrent requests. This is especially important on virtual servers that don’t have much memory to spare.
619 |PHP and Apache have a long history together. Apache is wildly configurable and has many available modules to extend functionality. It is a popular choice for shared servers and an easy setup for PHP frameworks and open source apps like WordPress. Unfortunately, Apache uses more resources than nginx by default and cannot handle as many visitors at the same time.
626 |Apache has several possible configurations for running PHP. The most common and easiest to setup is the prefork MPM with mod_php5. While it isn’t the most memory efficient, it is the simplest to get working and to use. This is probably the best choice if you don’t want to dig too deeply into the server administration aspects. Note that if you use mod_php5 you MUST use the prefork MPM.
627 |Alternatively, if you want to squeeze more performance and stability out of Apache then you can take advantage of the same FPM system as nginx and run the worker MPM or event MPM with mod_fastcgi or mod_fcgid. This configuration will be significantly more memory efficient and much faster but it is more work to set up.
628 |PHP has shared servers to thank for its popularity. It is hard to find a host without PHP installed, but be sure it’s the latest version. Shared servers allow you and other developers to deploy websites to a single machine. The upside to this is that it has become a cheap commodity. The downside is that you never know what kind of a ruckus your neighboring tenants are going to create; loading down the server or opening up security holes are the main concerns. If your project’s budget can afford to avoid shared servers you should.
636 |If you find yourself doing manual database schema changes or running your tests manually before updating your files (manually), think twice! With every additional manual task needed to deploy a new version of your app, the chances for potentially fatal mistakes increase. Whether you’re dealing with a simple update, a comprehensive build process or even a continuous integration strategy, build automation is your friend.
638 |Among the tasks you might want to automate are:
639 |Build tools can be described as a collection of scripts that handle common tasks of software deployment. The build tool is not a part of your software, it acts on your software from ‘outside’.
649 |There are many open source tools available to help you with build automation, some are written in PHP others aren’t. This shouldn’t hold you back from using them, if they’re better suited for the specific job. Here are a few examples:
650 |Phing is the easiest way to get started with automated deployment in the PHP world. With Phing you can control your packaging, deployment or testing process from within a simple XML build file. Phing (which is based on Apache Ant) provides a rich set of tasks usually needed to install or update a web app and can be extended with additional custom tasks, written in PHP.
651 |Capistrano is a system for intermediate-to-advanced programmers to execute commands in a structured, repeatable way on one or more remote machines. It is pre-configured for deploying Ruby on Rails applications, however people are successfully deploying PHP systems with it. Successful use of Capistrano depends on a working knowledge of Ruby and Rake.
652 |Dave Gardner’s blog post PHP Deployment with Capistrano is a good starting point for PHP developers interested in Capistrano.
653 |Chef is more than a deployment framework, it is a very powerful Ruby based system integration framework that doesn’t just deploy your app but can build your whole server environment or virtual boxes.
654 |Chef resources for PHP developers:
655 |Further reading:
660 |666 |668 |Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily — leading to multiple integrations per day. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.
667 |
– Martin Fowler
669 |There are different ways to implement continuous integration for PHP. Recently Travis CI has done a great job of making continuous integration a reality even for small projects. Travis CI is a hosted continuous integration service for the open source community. It is integrated with GitHub and offers first class support for many languages including PHP.
670 |Further reading:
671 |PHP is pretty quick by itself, but bottlenecks can arise when you make remote connections, load files, etc. Thankfully, there are various tools available to speed up certain parts of your application, or reduce the number of times these various time consuming tasks need to run.
679 |When a PHP file is executed, under the hood it is first compiled to bytecode (also known as opcode) and, only then, the bytecode is executed. If a PHP file is not modified, the bytecode will always be the same. This means that the compilation step is a waste of CPU resources.
681 |This is where Bytecode cache comes in. It prevents redundant compilation by storing bytecode in memory and reusing it on successive calls. Setting up bytecode cache is a matter of minutes, and your application will speed up significantly. There’s really no reason not to use it.
682 |Popular bytecodes caches are:
683 |There are times when it can be beneficial to cache individual objects in your code, such as with data that is expensive to get or database calls where the result is unlikely to change. You can use object caching software to hold these pieces of data in memory for extremely fast access later on. If you save these items to a data store after you retrieve them, then pull them directly from the cache for following requests, you can gain a significant improvement in performance as well as reduce the load on your database servers.
691 |Many of the popular bytecode caching solutions let you cache custom data as well, so there’s even more reason to take advantage of them. APC, XCache, and WinCache all provide APIs to save data from your PHP code to their memory cache.
692 |The most commonly used memory object caching systems are APC and memcached. APC is an excellent choice for object caching, it includes a simple API for adding your own data to its memory cache and is very easy to setup and use. The one real limitation of APC is that it is tied to the server it’s installed on. Memcached on the other hand is installed as a separate service and can be accessed across the network, meaning that you can store objects in a hyper-fast data store in a central location and many different systems can pull from it.
693 |Note that when running PHP as a (Fast-)CGI application inside your webserver, every PHP process will have its own cache, i.e. APC data is not shared between your worker processes. In these cases, you might want to consider using memcached instead, as it’s not tied to the PHP processes.
694 |In a networked configuration APC will usually outperform memcached in terms of access speed, but memcached will be able to scale up faster and further. If you do not expect to have multiple servers running your application, or do not need the extra features that memcached offers then APC is probably your best choice for object caching.
695 |Example logic using APC:
696 |<?php
697 | // check if there is data saved as 'expensive_data' in cache
698 | $data = apc_fetch('expensive_data');
699 | if ($data === false) {
700 | // data is not in cache; save result of expensive call for later use
701 | apc_add('expensive_data', $data = get_expensive_data());
702 | }
703 |
704 | print_r($data);
705 | Learn more about popular object caching systems:
706 |Rather than re-invent the wheel, many PHP developers use frameworks to build out web applications. Frameworks abstract away many of the low-level concerns and provide helpful, easy-to-use interfaces to complete common tasks.
753 |You do not need to use a framework for every project. Sometimes plain PHP is the right way to go, but if you do need a framework then there are three main types available:
754 |Micro-frameworks are essentially a wrapper to route a HTTP request to a callback, controller, method, etc as quickly as possible, and sometimes come with a few extra libraries to assist development such as basic database wrappers and the like. They are prominently used to build remote HTTP services.
760 |Many frameworks add a considerable number of features on top of what is available in a micro-framework and these are known Full-Stack Frameworks. These often come bundled with ORMs, Authentication packages, etc.
761 |Component-based frameworks are collections of specialized and single-purpose libraries. Disparate component-based frameworks can be used together to make a micro- or full-stack framework.
762 |As mentioned above “Components” are another approach to the common goal of creating, distributing and implementing shared code. Various component repositories exist, the main two of which are:
767 | 771 |Both of these repositories have command line tools associated with them to help the installation and upgrade processes, and have been explained in more detail in the Dependency Management section.
772 |There are also component-based frameworks, which allow you to use their components with minimal (or no) requirements. For example, you can use the FuelPHP Validation package, without needing to use the FuelPHP framework itself. These projects are essentially just another repository for reusable components:
773 |