Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Writing Portable PHP

Writing Portable PHP

Drew McLellan

February 19, 2015
Tweet

More Decks by Drew McLellan

Other Decks in Programming

Transcript

  1. Writing Portable PHP
    - DREW MCLELLAN -
    - CONFOO 2015 -

    View full-size slide

  2. Hello!
    flickr.com/photos/85520404@N03/9535499657

    View full-size slide

  3. Perch CMS
    PHP & MySQL content management system.
    ‘WordPress model’ - download and install on your own hosting.

    View full-size slide

  4. Listen up!
    This session is about shipping code into
    uncontrolled environments.
    It’s about coping with restrictive hosting, old PHP
    versions, lack of dependancy management and how
    PHP is working against us.
    It probably poses more problems than solutions.
    It may turn into a self-help group.

    View full-size slide

  5. You can switch.
    This session probably won’t help if your code is
    deployed with Composer.
    My tips are of no use to you if your answer to PHP 5.3 is
    to tell your user to upgrade.
    If your solution to a missing dependancy is to install the
    dependancy, I have nothing for you.
    You can switch rooms, we’re all friends here.

    View full-size slide

  6. Are we good?

    View full-size slide

  7. We love to hate PHP

    View full-size slide

  8. 60%
    - CMS USE -
    23%
    - ALL WEBSITES -

    View full-size slide

  9. This is common
    By numbers, the ship-and-deploy-to-bad-hosting
    model is the most common way PHP code is
    deployed.
    Despite this, PHP is actively hostile to this way
    of working.

    View full-size slide

  10. PHP is architecturally ill-
    suited for shipping code.
    Half-baked
    modularity!
    Configuration
    without detection!
    Offloading
    functionality
    to host OS!
    Non-standard
    as standard!

    View full-size slide

  11. PHP versions

    View full-size slide

  12. PHP versions
    13
    25
    38
    50
    5.2 5.3 5.4 5.5 5.6
    2%
    12%
    45%
    35%
    7%
    - PERCH CMS USERS -

    View full-size slide

  13. Hosts don’t like to
    update PHP
    Historically, PHP updates have caused
    incompatibility with common software.
    Hosts are nervous to update a server, break
    sites and anger their customers.
    But they’re usually happy to move a customer
    to a newer server with newer PHP on request.

    View full-size slide

  14. PHP has to move
    forward.

    View full-size slide

  15. ext/mysql
    1. Hosting company tests PHP 7, looks good.
    2. Deploys PHP 7 on new servers.
    3. New customers migrate old sites to new hosting.
    4. Sites don’t work. Tech support freaks out.
    5. Host considers PHP 7 unsafe, rolls back to PHP 5.
    6. Five more years of winter.

    View full-size slide

  16. If you ship code, you
    have to deal with old PHP
    - AND NEW PHP -

    View full-size slide

  17. Safe mode
    Deprecated in PHP 5.3, removed in 5.4
    Don’t rely on being able to keep files outside of
    the web root.
    Don’t rely on reading a file unless you created it.
    cURL requests with follow_location option fail.
    Non-standard
    as standard!

    View full-size slide

  18. Magic Quotes
    Deprecated in PHP 5.3, removed in 5.4
    Was a misguided security feature.
    Designed without considering portability.
    Continues to me an enormous PITA.
    Non-standard
    as standard!

    View full-size slide

  19. Magic Quotes
    That’s life.
    That\’s life.

    That’s life.

    View full-size slide

  20. Magic Quotes
    str.replace(‘this\’n\’that’)
    str.replace(\’this\\\’n\\\’that\’)

    str.replace(‘this\’n\’that’)
    str.replace(‘this’n’that’)

    View full-size slide

  21. Magic Quotes
    So we just need to ask PHP if magic quotes
    have been applied to the input…
    … oh wait.
    get_magic_quotes_gpc();
    get_magic_quotes_runtime();
    Configuration
    without detection!

    View full-size slide

  22. Mixed PHP versions
    Your code might run on different PHP versions
    between development and live environments.
    Web requests and CLI might use different
    versions.
    It’s not enough to configure, you have to
    detect.

    View full-size slide

  23. Mixed PHP versions
    if (modern_php_test()){
    $feature = [];
    } else {
    $feature = array();
    }
    BEWARE!

    View full-size slide

  24. Modularity
    - HALF-BAKED -

    View full-size slide

  25. Modularity issues
    Common functionality is provided by optional
    extensions.
    Missing extensions can’t be dynamically loaded.
    Core functionality can be disabled.
    No structured way to test the environment.

    View full-size slide

  26. Using a database
    Let’s use a MySQL database!
    We may have mysql, mysqli or PDO.
    So, mysqli or PDO then.
    mysqli is optional!
    PDO is enabled by default from PHP 5.1

    View full-size slide

  27. PDO + MySQL
    PDO is enabled by default, but can be disabled.
    PDO’s MySQL driver is optional.
    Sooooo…

    View full-size slide

  28. Both?
    if (defined('PDO::MYSQL_ATTR_LOCAL_INFILE')) {
    return new PerchDB_PDO;
    }else{
    return new PerchDB_MySQLi;
    }

    View full-size slide

  29. SQLite!
    “PDO and the PDO_SQLITE driver is enabled by
    default as of PHP 5.1.0.”
    SQLite DB is just a file, and needs to be kept
    somewhere safe.
    PHP provides no mechanism like it does for,
    e.g. session files.

    View full-size slide

  30. Manipulating images
    This is something websites do.
    PHP is for making websites!
    So PHP can manipulate images, right?
    Well, we need to talk about that…

    View full-size slide

  31. GD & Imagick
    Two common extensions: GD and Imagick
    Usually one or the other, sometimes both or
    sometimes none.
    You need code for both: use a library if you
    can.
    e.g. http://image.intervention.io

    View full-size slide

  32. HTTP requests
    PHP is a web scripting language.
    Let’s make an HTTP request!
    Yeah, about that…

    View full-size slide

  33. HTTP requests
    sockets - works! Pretty low level.
    cURL - optional. High level and useful.
    file_get_contents() - sometimes works. Basic.
    Libraries?

    View full-size slide

  34. HTTP libraries
    Lots of choices - many are just wrappers
    around cURL.
    Others offer a transport choice, but no
    detection (e.g. Guzzle)
    ‘Requests’ looks good in this regard.
    http://requests.ryanmccue.info

    View full-size slide

  35. No way to load extensions
    If something is missing, it’s missing.
    You can’t load it, import it, require it.
    You just have to deal with it.

    View full-size slide

  36. Disabling core functionality
    PHP gives the system admin the ability to
    disable core functionality that is “always”
    there.
    Detecting what’s available is impractically
    cumbersome.

    View full-size slide

  37. Disabling core functionality
    if (function_exist(‘count’) && 

    strpos(ini_get(‘disable_functions’),
    ‘count’)===false) {
    $number_of_items = count($my_array);
    }

    View full-size slide

  38. Disabling core functionality
    if (function_exist(‘curl_init’)) {
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $result = curl_exec($ch);
    } BEWARE!

    View full-size slide

  39. Disabing other random stuff
    Remember, sysadmins be crazy.
    We’ve seen GD available, but
    imagecreatefrompng() simply missing.
    Good luck out there.

    View full-size slide

  40. Bad hosting
    Configuration
    without detection!

    View full-size slide

  41. Bad hosting
    Expect the unexpected!
    Hosts do crazy things for reasons you’ll never
    understand.
    Don’t try to understand. Just accept.

    View full-size slide

  42. Sessions
    Many shared hosts like to give users their own
    PHP sessions folder.
    But then leave it up to the user to configure
    the session_save_path.
    By default, sessions will start but won’t persist
    any data.

    View full-size slide

  43. cURL
    Some hosts will disable or not install cURL,
    which is their choice.
    Others will install and enable cURL.
    A very special third group install and enable
    cURL and then block it at their firewall.

    View full-size slide

  44. Cross-platform
    Offloading
    functionality
    to host OS!

    View full-size slide

  45. PHP on Windows
    PHP on Windows is a real thing.
    It’s used more in development environments
    than in production.
    Users will set up WAMP or similar on their
    Windows desktop, and then deploy to a *nix
    hosting environment.

    View full-size slide

  46. Paths
    PHP expects you to know how to formulate file
    system paths for the host.
    Sometimes the file system will forgive errors
    (e.g. slashes vs back-slashes)
    Sometimes it won’t.

    View full-size slide

  47. Paths
    Wrap all your paths so they can be translated
    for the current file system.
    Then write your paths consistently in one style.

    View full-size slide

  48. Paths
    function file_path($path) {
    if (DIRECTORY_SEPARATOR!='/') {
    $path = str_replace('/', DIRECTORY_SEPARATOR, $path);
    }
    return $path;
    }

    View full-size slide

  49. Dates
    Simple date formatting is fraught with danger.
    strftime() passes through to the host OS.
    Some formatting codes will work with your
    host OS. Some will completely fail and return
    nothing, or throw a notice.

    View full-size slide

  50. Dates
    I like to define some set formats that I think
    should work broadly, but let the user redefine
    them for edge-cases.

    View full-size slide

  51. Dates
    echo strftime(PERCH_DATE_LONG, $time);

    View full-size slide

  52. Watch out for ‘Windows’
    Get in the habit of watching out for references to
    Windows in the PHP manual.
    It will help you spot potential Windows issues, but
    also is a warning of functionality that gets passed
    to the host OS.
    These will often be affected by configuration, not
    just platform.

    View full-size slide

  53. File systems and MySQL
    MySQL is not immune.
    Don’t mix case in object names (e.g. table
    names).
    MySQL’s case sensitivity is dependant on the
    host file system.

    View full-size slide

  54. Thanks!
    @drewm

    View full-size slide