PHP SA 2014 - Releasing Your Open Source Project
Upcoming SlideShare
Loading in...5
×
 

PHP SA 2014 - Releasing Your Open Source Project

on

  • 646 views

Learn about how to write open source libraries people won't (completely) hate.

Learn about how to write open source libraries people won't (completely) hate.

Statistics

Views

Total Views
646
Views on SlideShare
635
Embed Views
11

Actions

Likes
0
Downloads
6
Comments
0

1 Embed 11

http://librosweb.es 11

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

PHP SA 2014 - Releasing Your Open Source Project PHP SA 2014 - Releasing Your Open Source Project Presentation Transcript

  • Releasing Your Open Source Project How to write libraries people won't (completely) hate By @thomas_shone
  • WARNING ● Opinionated ● Rambling ● Foul-Mouthed ● Ugly Slides ● Don't feed after midnight
  • 00. Introduction ● No formal education in PHP ● Learnt PHP the hard way ● This talk is about the process ● Connect with personalities
  • 00. Introduction
  • 00. Introduction <?php function isUrlSafe($api_key, $url) { if (!filter_var($url, FILTER_VALIDATE_URL)) { throw new Exception('Invalid URL specified.') } $api_uri = 'https://sb-ssl.google.com/' . 'safebrowsing/api/lookup?client=api&apikey=' . $api_key . '&appver=1.0&pver=3.0&url=' . urlencode($url); $result = file_get_contents($api_uri); return strpos($result, 'malware') === false && strpos($result, 'phishing') === false; } When you've finished reading this code, touch your nose so I know when everyone is done.
  • 10. Security ● Shouldn't be left till last ● Unsure of how to do it properly ● Worst thing that can happen to insecure open source code is it becomes popular
  • 10. Security ● Shouldn't be left till last ● Unsure of how to do it properly ● Worst thing that can happen to insecure open source code is it becomes popular
  • 01. Security ● Shouldn't be left till last ● Unsure of how to do it properly ● Worst thing that can happen to insecure open source code is it becomes popular
  • 01. Security ● Joomla! – 5/133 versions secure – 85 vulnerabilities – 0/322 of scanned sites secured ● WordPress – 2/322 versions secure – 54 vulnerabilities – 313/589 of scanned sites secure
  • 01. Secure Communication What questions do we need to ask to ensure our communication is secure?
  • 01. Secure Communication 1. Can C overhear what A and B are saying? BA C
  • 01. Secure Communication 2. Is A sure s/he is talking to B and C isn't standing in the middle? BA C
  • 01. Secure Communication 3. Does A trust B not to tell C? BA C
  • 01. Secure Communication ● Certificate file sourced from https://github.com/guzzle/guzzle/blob/master/src/cacert.pem ● disable_compression only available in PHP 5.4.13+ (prevents CRIME/BREACH attacks) ● Not required with PHP 5.6+ thanks to this guy... $context = stream_context_create([ 'ssl' => [ 'verify_peer' => true, 'verify_depth' => 5, 'cafile' => 'cacert.pem', 'CN_match' => 'sb-ssl.google.com', 'disable_compression' => true, ] ]); $result = file_get_contents($api_uri, false, $context);
  • 01. Personality Daniel Lowrey (@rdlowrey) PHP SSL/TLS Contributor Saving us from ourselves Itotallygotpermissiontousethisphoto
  • 02. Hosting ● phpclasses.org ● sourceforge.net ● pear.php.net ● bitbucket.org ● github.com
  • 02. Hosting ● phpclasses.org - FUCK NO! ● sourceforge.net - HELL NO! ● pear.php.net - No ● bitbucket.org - No ● github.com - Yes
  • 03. Managing your source ● Source control (already determined) ● Version ● License
  • 03. Credentials ● .gitignore to exclude sensitive data ● If you've pushed sensitive data to github, change your credentials asap https://help.github.com/articles/remove-sensitive-data Don't be that guy
  • 03. Licensing ● MIT – Do whatever you want with it – Must attribute – Don't blame me if it causes a zombie outbreak ● Apache – Same as MIT – contributors grants patent rights to users ● GPL – Must release any changes or improvements – Can't change license – Ditto with the zombies http://choosealicense.com/
  • 03. Versioning MAJOR.MINOR.PATCH-STABILITY ● Breaking backward compatibility? Increase MAJOR ● Adding backwards compatible feature? Increase MINOR ● Adding bugfix? Increase PATCH ● Not production ready? Add stability value (alpha, beta, preview) http://semver.org/
  • 04. Package Management
  • 04. Package Management ● PEAR – No space for alternatives – High requirement levels – Package signing ● Composer – Easy to install/update dependencies – Version locking – Autoloading – Your package becomes smaller – Package signing (almost) – Doubles as a distribution platform (https://packagist.org )
  • 04. Package Management ● PEAR - NO – No space for alternatives – High requirement levels – Package signing ● Composer - YES – Easy to install/update dependencies – Version locking – Autoloading – Your package becomes smaller – Package signing (almost) – Doubles as a distribution platform (https://packagist.org )
  • 04. Composer $ mkdir safebrowser && cd safebrowser $ curl -s http://getcomposer.org/installer | php #!/usr/bin/env php All settings correct for using Composer Downloading... Composer successfully installed to: /home/project/composer.phar Use it: php composer.phar
  • 04. Composer $ php composer.phar init Welcome to the Composer config generator This command will guide you through creating your composer.json config. Package name (<vendor>/<name>) [thomas/project]:xsist10/SafeBrowsing Description []: Google Safe Browsing Client Author [Thomas Shone <xsist10@gmail.com>]: Minimum Stability []: License []: MIT
  • 04. Composer { "name": "xsist10/safebrowser", "description": "Google SafeBrowser Client", "license": "MIT", "authors": [ { "name": "Thomas Shone", "email": "xsist10@gmail.com" } ], "require": { }, "autoload": { "psr-4": { "xsist10SafeBrowsing": "src/" } } }
  • 04. Composer $ php composer.phar install Loading composer repositories with package information Installing dependencies (including require-dev) Nothing to install or update Generating autoload files $ vi index.php <?php require 'vendor/autoload.php';
  • 04. Don't commit vendor/ # Your code src/[Your Library] vendor/[Dependencies] $ echo "vendor" >> .gitignore # Someone using your library src/[Their Project Code] vendor/xsist10/SafeBrowsing/[Your Library] vendor/[Your Library Dependencies] vendor/[Their Dependencies] Some of these might be the same # You don't want this vendor/xsist10/SafeBrowsing/[Your Library]/vendor/
  • 04. Composer $ mkdir src $ vi src/SafeBrowsing.php <?php namespace xsist10SafeBrowsing; class SafeBrowsing { public function __construct($api_key) { $this->api_key = $api_key; } public function isUrlSafe($url) { // ... } }
  • 04. Composer <?php require 'vendor/autoload.php'; use xsist10SafeBrowsingSafeBrowsing; $safeBrowsing = new SafeBrowsing($api_key); $safeBrowsing->isUrlSafe('www.example.com');
  • 04. List on Packagist
  • 04. List on Packagist $ php composer.phar require xsist10/safebrowser=dev-master
  • 04. Setup Webhook
  • 04. Setup Webhook
  • 04. Setup Webhook
  • 04. Setup Webhook
  • 04. Package Signing ● Currently being implemented in Composer – https://github.com/composer/composer/pull/2814 ● Ensure that the package you're installing hasn't been tampered with, like: – Ruby Gem installs – PEAR libraries – Linux packages (deb, rpm, yum) – Windows binaries
  • 04. Package Signing # When you first setup your project $ php composer.phar create-keys --directory /path/ --prefix=mykey --passphrase passphrase to encrypt the private key: $ php composer.phar add-dev-key /path/mykey-private.pem $ php composer.phar sign-dev-keys /path/mykey-private.pem # Last thing you do before you release a new version $ php composer.phar sign /path/mykey-private.pem Enter a passphrase if the private key is encrypted: $ git commit -m “Updated keys” keys.json manifest.json $ git push # Tag you release immediately
  • 04. Version
  • 04. Personality Pádraic Brady (@padraicb) Zend Framework / Composer contributor Working on the signing code Thisguyissoawesomethattheinternetcan't containpicturesofhim.
  • 05. Design Patterns ● Increase flexibility without having to modify the library code ● Provide rules on how to extend
  • 05. Strategy
  • 05. Strategy <?php namespace xsist10SafeBrowsingStrategy; interface Strategy { public function execute($url, $param); } https://en.wikipedia.org/wiki/Strategy_pattern
  • 05. Strategy <?php namespace xsist10SafeBrowsingStrategy; class Get implements Strategy { public function execute($url, $param) { $context = stream_context_create([ 'ssl' => [ 'verify_peer' => true, 'cafile' => 'path/to/cafile', 'CN_match' => 'sb-ssl.google.com' ] ]); $query = $url . '?' . http_build_query($param); return file_get_contents($query, false, $context); } }
  • 05. Strategy <?php namespace xsist10SafeBrowsingStrategy; class Post implements Strategy { public function execute($url, $param) { // Do some curl init stuff ... // Do your security! curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($curl, CURLOPT_CAINFO, 'path/to/cafile'); $result = curl_exec($curl); $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); // check some result checks first ... return $result; } }
  • 05. Strategy <?php require 'vendor/autoload.php'; use xsist10SafeBrowsingSafeBrowsing; use xsist10SafeBrowsingStrategyGet; $sb = new SafeBrowsing($api_key, new Get()); $sb->isUrlSafe('www.example.com'); use xsist10SafeBrowsingStrategyPost; $sb = new SafeBrowsing($api_key, new Post()); $sb->isUrlSafe('www.example.com');
  • 05. Chain of Responsibility
  • 05. Chain of Responsibility <?php namespace xsist10SafeBrowsingStrategy; use Exception; class UnavailableException extends Exception {} https://en.wikipedia.org/wiki/Strategy_pattern
  • 05. Chain of Responsibility <?php namespace xsist10SafeBrowsingStrategy; class Get implements Strategy { public function execute($url, $param) { if (!ini_get('allow_url_fopen')) { throw new UnavailableException(); } // ... } }
  • 05. Chain of Responsibility <?php namespace xsist10SafeBrowsingStrategy; class Post implements Strategy { public function execute($url, $param) { if (!function_exists('curl_init')) { throw new UnavailableException(); } // ... } }
  • 05. Chain of Responsibility <?php namespace xsist10SafeBrowsing; use xsist10SafeBrowsingStrategyStrategy; class Chain implements Strategy { public function append(Strategy $strat) { $this->chain[] = $strat; } public function execute($url, $param) { foreach ($this->chain as $strategy) { try { return $strategy->get($url, $param); } catch (UnavailableException $exception) { // We can ignore and move to the next } } throw new Exception('No available strategy.'); } }
  • 05. Put the chain links together <?php // ... use xsist10SafeBrowsingChain; $chain = new Chain(); $chain->append(new Post()); $chain->append(new Get()); $sb = new SafeBrowsing($api_key, $chain); $sb->isUrlSafe('www.example.com'); // This still works $sb = new SafeBrowsing($api_key, new Get()); $sb->isUrlSafe('www.example.com');
  • 05. The start of something beautiful <?php // ... use SomeOtherGuySomeOtherPackageCache; $chain = new Chain(); $chain->append(new Cache()); $chain->append(new Post()); $chain->append(new Get()); $sb = new SafeBrowsing($api_key, $chain); $sb->isUrlSafe('www.example.com');
  • 05. Personality Martin Fowler (@martinfowler) Design Pattern Tamer http://www.martinfowler.com/ Hegetssuperpowersfromhishat
  • So what next? Shamelessly copied from http://thephpleague.com/ ● Follow PSR-2, we use League as our PSR-0 namespace. ● List on Packagist, we list with league as the vendor namespace. ● Shove code in a src folder. ● Write unit tests. Aim for at least 80% coverage for v1.0. ● DocBlock all the things. ● Semantic versioning must be used to manage version numbers. ● Use Travis-CI to automatically check coding standards and run tests. ● Have an extensive README.
  • 06. Why Tests? ● You will always find bugs ● Confidence in libraries ● Prevent regressions ● Ensure new features have been thoroughly vetted
  • 06. PHPUnit $ php composer.phar require --dev phpunit/phpunit=4.0.*@dev ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) ... - Installing phpunit/phpunit (4.0.x-dev fca5bc6) Cloning fca5bc6a50d09b26db280c5cc3c84978c9cace3f phpunit/phpunit suggests installing phpunit/php-invoker (~1.1) Writing lock file Generating autoload files
  • 06. PHPUnit $ vi phpunit.xml <?xml version="1.0" encoding="UTF-8"?> <phpunit backupGlobals="false" convertErrorsToExceptions="true" convertWarningsToExceptions="true" convertNoticesToExceptions="true" mapTestClassNameToCoveredClassName="true" bootstrap="vendor/autoload.php" strict="true" verbose="true" colors="true"> <testsuites> <testsuite> <directory>./tests</directory> </testsuite> </testsuites> </phpunit> $ mkdir tests $ vi phpunit.xml
  • 06. PHPUnit $ vi phpunit.xml$ ./vendor/bin/phpunit PHPUnit 4.0.13 by Sebastian Bergmann. Configuration read from /path/to/project/phpunit.xml Time: 116 ms, Memory: 2.00Mb No tests executed!
  • 06. First Tests use xsist10SafeBrowsingSafeBrowsing; use xsist10SafeBrowsingStrategyChain; class SafeBrowsingTest extends PHPUnit_Framework_TestCase { public function testInvalidUrl() { $chain = new Chain(); $safeBrowsing = new SafeBrowsing('', $chain); $message = 'Invalid URL specified.'; $this->setExpectedException('Exception', $message); $safeBrowsing->isUrlSafe('invalid-url'); } } $ vi tests/SafeBrowsingTest.php
  • 06. First Tests public function testSecure() { $mock = $this->getMockBuilder( 'xsist10SafeBrowsingStrategyChain', ['execute'] )->getMock(); // API returns an empty result if the site is secure $mock->expects($this->once()) ->method('execute') ->will($this->returnValue('')); $safeBrowsing = new SafeBrowsing('', $mock); $url = 'http://www.google.com'; $response = $safeBrowsing->isUrlSafe($url); $this->assertTrue($response); }
  • 06. First Tests $ vi phpunit.xml$ ./vendor/bin/phpunit PHPUnit 4.0.13 by Sebastian Bergmann. Configuration read from /path/to/project/phpunit.xml ..... Time: 568 ms, Memory: 4.00Mb OK (5 tests, 9 assertions)
  • 06. Testing Resources ● Can't mock out resources ● Wrap resources in class and mock the class ● Wait! Don't write from scratch. Use your package manager!
  • 06. cURL wrapper $ ./composer.phar search curl ext-curl The curl PHP extension lib-curl The curl PHP library kdyby/curl Curl wrapper for Nette Framework shuber/curl PHP Wrapper for Curl comvi/curl Work with remote servers via cURL much easier than using the native PHP bindings. anlutro/curl Simple OOP cURL wrapper. jyggen/curl A simple and lightweight cURL library with support for multiple requests in parallel. bca/curl cURL wrapper for PHP applications. unikent/curl Laravel Curl Helper Library. mogetutu/curl Simple Curl PHP Helper Library sweelix/curl PHP 5.3+ simple curl requestor lib/curl A simple cURL wrapper for PHP dvelopment/curl PHP OOP wrapper for cURL requests php-curl-class/php-curl-class PHP Curl Class is an object-oriented wrapper of the PHP cURL extension.
  • 06. cURL wrapper $ php composer.phar require shuber/curl=dev-master ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) - Installing shuber/curl (dev-master 6624992) Cloning 6624992df201f9fd7262080117385dd09b0ecd2b Writing lock file Generating autoload files
  • 06. Personality Chris Hartjes (@grmpyprogrammer) Testing advocate Being grumpy... so we don't have to Itotallydidn'tgetpermissiontousethisphoto
  • 06. Personality Howhereactstoalackoftests.
  • 07. Code Coverage ● Ensure you test all use cases ● Useful to spot code smell ● Helpful in identifying dead/unreachable code ● Improves confidence in library
  • 07. Coverage Report <phpunit ...> ... <logging> <log type="coverage-html" target="build/report" charset="UTF-8" highlight="false" LowUpperBound="35" HighLowerBound="70" /> </logging> <filter> <whitelist> <directory>src</directory> </whitelist> </filter> </phpunit> $ echo “build” >> .gitignore $ vi phpunit.xml
  • 07. Coverage Report
  • 07. Coverage Report
  • 07. Coverage Report
  • 07. Ignore coverage ● Ignore whole class/function – @codeCoverageIgnore ● Ignore certain lines of code – // @codeCoverageIgnoreStart – // @codeCoverageIgnoreEnd ● Use responsibly
  • 08. Continuous Integration ● Make sure your development branch is always in a deployable state. ● Ingredients: Tests, High Coverage, Automation
  • 08. Travis-CI language: php before_script: - wget http://getcomposer.org/composer.phar - php composer.phar install --dev php: - 5.5 - 5.4 - hhvm script: phpunit $ vi .travis.yml
  • 08. CLI Tools ● Copy paste detector ● Code Sniffer ● Mess Detector ● And lots more at http://phpqatools.org/
  • 07 – Copy/paste detector $ php composer.phar require --dev sebastian/phpcpd=dev-master ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) - Installing sebastian/phpcpd (dev-master a946215) Cloning a9462153f2dd90466a010179901d31fbff598365 Writing lock file Generating autoload files $ ./vendor/bin/phpcpd src/ phpcpd 2.0.1 by Sebastian Bergmann. 0.00% duplicated lines out of 195 total lines of code. Time: 32 ms, Memory: 2.75Mb
  • 08. Code Sniffer $ php composer.phar require --dev squizlabs/php_codesniffer=dev-master ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) - Installing squizlabs/php_codesniffer (dev-master 623905c) Cloning 623905ce571d64a8cb873826d47b81321cd55011 Writing lock file Generating autoload files $ ./vendor/bin/phpcs -i The installed coding standards are PSR1, PHPCS, Squiz, PEAR, Zend, MySource and PSR2 $ ./vendor/bin/phpcs --standard=PSR2 src/ [WALL OF TEXT]
  • 08. Select a Standard $ ./vendor/bin/phpcs --standard=PSR2 src/ FILE: /path/to/project/SafeBrowsing/src/SafeBrowsing.php ------------------------------------------------------------------- FOUND 3 ERROR(S) AFFECTING 2 LINE(S) ------------------------------------------------------------------- 17 | ERROR | Opening brace should be on a new line 22 | ERROR | Visibility must be declared on method "isUrlSafe" 22 | ERROR | Opening brace should be on a new line ------------------------------------------------------------------- [WALL OF TEXT OMITTED]
  • 08. Custom Standard $ ./vendor/bin/phpcs --standard=/path/to/own/standard src/ FILE: /path/to/project/SafeBrowsing/src/SafeBrowsing.php ------------------------------------------------------------------- FOUND 1 ERROR(S) AFFECTING 1 LINE(S) ------------------------------------------------------------------- 1 | ERROR | Homage to Cthulhu missing from doc header -------------------------------------------------------------------
  • 08. Mess Detector $ php composer.phar require --dev phpmd/phpmd=1.4.* ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) - Installing phpmd/phpmd (1.4.1) Downloading: 100% Writing lock file Generating autoload files $ ./vendor/bin/phpmd src text codesize,unusedcode,naming,design Strategy/Get.php:9 Classes should not have a constructor method with the same name as the class
  • 08. Taking it further ● Jenkins – http://jenkins-ci.org/ – Automate all the things ● Behat – http://behat.org/ – Cucumber syntax – Mink extension for website testing – Write human-readable use cases
  • 08. Behat and Mink Feature: Test the login page In order to ensure that customer can use our system I need to make sure that they can log in successfully Scenario: Can I log in with valid details Given I am on the “www.mywebsite.com” When I click on “Login” And I fill “username” with “bob” And I fill “password” with “Password1” And I press “Login” Then I should see “Login Successful”
  • 09. Flair ● General badges (versions, license, etc) – https://poser.pugx.org/ ● Build status – https://travis-ci.org ● Code Coverage – https://coveralls.io ● Code Analysis – https://insight.sensiolabs.com/analyses – https://scrutinizer-ci.com/
  • 10. Engage ● Write a useful README.md – First thing you see on Github – How to install – How to use
  • 10. Engage with developers ● Encourage fork/pull requests – Make sure they add tests – Make sure the old tests still pass – Travis-CI makes this simple
  • 10. Engage with developers ● Promote your library – Twitter? – Google Plus? – I have no idea. I'm still figuring this out. I'm a developer dammit!
  • Homework ● Docblocks ● phing/ant to automate CLI tools ● Git pre-commit hooks to run tests
  • Social Awareness Too many pasty white guys @phpwomen http://phpwomen.org/
  • Questions? Twitter: @thomas_shone Github: https://github.com/xsist10 https://github.com/xsist10/SafeBrowsing