Category: PHP

Using HTTP/2 with PHP 7 on Mac

if you want to use HTTP/2 with PHP on OS X, you need a version of curl compiled with HTTP/2 support. You can then link your PHP's curl extension to this version.

The easiest way to do this is to use Homebrew:

At the time of writing, this will install PHP 7.0.10 with Curl 7.50.1:

Using Curl on the command line

If you want to use your shiny new curl from the command line, then the easiest way to do this is:

You can now do:

and you should get:

(at the time of writing!)

Using Guzzle to test HTTP/2 is working

To prove it works in PHP, use Guzzle!:

testhttp2.php:

Run this PHP code at the command line:

As we've turned on debugging, the output looks like this:

The key things to notice:

We tell the server that we want HTTP/2 (h2), but can accept HTTP/1.1. If the server doesn't support HTTP/2 it will send back HTTP/1.1

This is a good sign!

The response's status line is:

The version number is 2 and we got a 200, so all is OK!

Everything is working as intended.

Passing on the baton

Lorna Mitchell has posted Joind.in Needs Help:

For the last 6 years I've been a maintainer of this project, following a year or two of being a contributor. Over the last few months, myself and my comaintainer Rob Allen have been mostly inactive due to other commitments, and we have agreed it's time to step aside and let others take up the baton.

I'm proud of my contributions to joind.in as a contributor and maintainer. I couldn't have done it without Lorna's encouragement (and willingness to point out my mistakes!). The project has had a significant influence in my Open Source journey as my work has led to my leadership role in Slim Framework and interest in writing APIs.

If you want to guide the next stage of joind.in's journey, please find us in #joind.in on Freenode IRC.

Checklist for releasing Slim

Release process for Slim so that I don't forget any steps; based on a check list created by Asgrim. I should probably automate some of this!

Preparation:

  • Ensure all merged PRs have been associated to the tag we're about to release.
    Find them via this search: [is:pr is:closed no:milestone is:merged].
  • Close the milestone on GitHub.
  • Create a new milestone for the next patch release.
  • Ensure that you have the latest master & that your index is clean.
  • Find the ID of the current milestone. This is the numeric id found in the URL of the milestone detail page (e.g. 34).
  • Generate the changeling using changelog_generator & copy to clipboard:
    changelog_generator.php -t {your-github-api-token} -u slimphp -r Slim -m {ID} | pbcopy

Tag and release:

  • Edit App.php and update the VERSION constant to the correct version number. Commit the change.
  • Tag the commit: git tag -s {x.y.z} & paste the change log generated above into the tag message.
  • Update App.php again and set the VERSION constant to {x.y+1.0}-dev & commit.
  • Push the commits and the new tag: git push --follow-tags
  • Go to the releases page and click "Draft a new release":
    • Enter the tag name and ensure that you see a green tick and "Existing tag" appear.
    • Set the release title to the same as the tag name.
    • Paste the change log generated above into the release notes box (it is already formatted with Markdown).
    • Click "Publish release".
  • Write announcement blog post for website & publish.

Standalone Doctrine Migrations redux

Since, I last wrote about using the Doctrine project's Migrations tool independently of Doctrine's ORM, it's now stable and much easier to get going with.

Installation and configuration

As with all good PHP tools, we simply use Composer:

This will install the tool and a script is placed into vendor/bin/doctrine-migrations.

To configure, we need to add two files to the root of our project:

migrations.yml:

This file sets up the default configuration for Migrations. The most important two settings are table_name which is the name of the database table holding the migration information and migrations_directory which is where the migration files will be stored. This directory name may be a relative path (relative to the directory where migrations.yml is stored, that is).

migrations-db.php:

This file is simply the standard DBAL configuration for a database connection. In this case, I'm using SQLite. Again, the path is relative.

Using Migrations

Migrations is a command line tool called doctrine-migrations that has been installed into the vendor/bin/ directory. Running the tool without arguments will give you helpful information:

The two important command are: migrations:generate and migrations:migrate.

Creating a migration

To generate a new migration, we run:

This will create a new file for us in our migrations directory which we then need to fill in. There are two methods class: up() and down() and the rule is that whatever we do in up() must be reversed in down().

For example to create a new table, we code it like this:

If you want to write your schema changes as SQL, then use the $this->addSql() method.

We can also populate the newly created table adding the postUp() method to the class. As its name suggests, the code in the method is execute after the code in up(). In postUp() we access the connection property and then call the appropriate methods. For example:

Alternatively, we could have used executeQuery() and written it as SQL:

Running the migrations

To update the database to the latest migration we run the migrations:migrate command. This will run the up() method on all migration files that haven't already been run. For example:

In this case, I have two migration files in my migrations directory and started with an empty database.

That's it

That's all there is to it. Migrations is very easy to use as a standalone tool and worth considering for your database migrations.

View header and body with curl

I recently discovered the -i switch to curl! I have no idea why I didn't know about this beforeā€¦

Curl is one of those tools that every developer should know. It's universal and tends to be available everywhere.

When developing APIs, I prefer to use curl to view the output of a request like this:

-v is for verbose and so you get told all the information you could possibly want. However, usually, I only want to know the response's headers and body.

Enter the -i switch!

Much better!

-i is for include and from the man page:

Include the HTTP-header in the output. The HTTP-header includes things like server-name, date ofthe document, HTTP-version and more…

This is exactly what I want without the information that I don't!

Filtering the PSR-7 body in middleware

Sometimes, there's a requirement to alter the data in the Response's body after it has been created by your controller action. For example, we may want to ensure that our brand name is consistently capitalised.

One way to do this is to create middleware that looks like this:

This works perfectly, so if my response body contains "I consult through my company, nineteen feet.", then the output of the $brandFilter middleware is "I consult through thought my company, Nineteen Feet.", which is exactly what we want.

That's great, but what happens if the new string is shorter than the old one? For instance, suppose I want to replace all uses of "nineteen feet" with "19FT".

Using the same middleware, but changing the str_ireplace call with:

creates this output:

That's not quite what we wanted! This result is because the new string is shorter, so the characters from the old string are still in the PHP stream and as we haven't change the length, they are still there. The PSR-7 StreamInterface doesn't allow us access to the underlying stream, so we can't call ftruncate on it.

Hence, the easiest solution is to replace the Response's PSR-7 StreamInterface object with a new one containing what we need:

The output is now what we expect:

Slim 3.4.0 now provides PSR-7!

I've been neglecting Slim's PR queue recently, so this weekend I dedicated a lot of time to merging all the good work that our contributors have done. As a result, I'm delighted to release version 3.4.0!

This release has a larger set of changes in it than I would have ideally liked which is a direct consequence of having gone two months between releases rather than one.

One particularly interesting addition that we have a made this release is adding a provide section to our composer.json file:

This means that we have informed Composer that Slim provides a valid implementation of the interfaces in psr/http-message-implementation virtual package that defines the PSR-7 interfaces.

This means that when you install a Composer package that requires psr/http-message-implementation in your Slim project, then Composer will now recognise that Slim satisfies this requirement and won't insist you install another PSR-7 implementation just for package resolution!

There's lots of other goodies in 3.4.0, so check out the release notes and upgrade!

Overriding Slim 3's error handling

Slim 3 registers two error handers:

This means that if you want to override the default error handlers, you need to override both error handlers with your own code.

Each error handler is a callable. The signatures are:

  • errorHandler: function ($request, $response, $exception)
  • phpErrorHandler: function ($request, $response, $error)

To override a error handler, simply register a new callable with the Container:

If you don't want to repeat yourself, you can register the phpErrorHandler like this:

Note that you can register any PHP callable, so a class with an __invoke() method also works.

Handling PHP notices

As an aside, Slim 2's error handler catches PHP notices for you (which can be infuriating or very useful!). Slim 3 doesn't do this by default, so if you want to catch PHP notices then you need to register your own error handler like this:

That's all there is to it.

A few composer tips

I recently learned about a couple of features of composer that I thought I'd write down here so that I don't forget them! I also had to deal with a conflict in composer.lock recently, so I've noted down how I solved that too.

List installed versions

To list the current versions of all installed dependencies:

The output looks something like:

Very useful for working out exactly what's installed.

Set PHP version

To set the version of PHP that composer will use to resolve dependencies, add this to your composer.json file:

You can now run composer update on a PHP 7 installation and it will create a composer.lock file suitable for a server running PHP 5.6.19.

Resolving a conflict in composer.lock

When you merge a feature branch into develop and get a conflict in composer.lock, I've found these strategies work best for me:

Just the hash

If the only conflict is in the "hash" and "content-hash" lines, then pick either choice and then run:

Any other conflict

For any other conflict where you want to keep the current set of versions on develop:

  1. Retrieve the correct lock file for develop: git merge --ours
  2. Add in each new dependency in the merged composer.json that's not in the original develop's composer.json using

The end result is a composer.lock file with the original information from develop along with the new packages from the feature branch.

Determining the image type of a file

One thing I learnt recently which I probably should have known already is that getimagesize() returns more than just the width and height of the image.

I've always used it like this:

However, getimagesize() also returns up to 5 more pieces of information.

Interestingly, the data array is a mix of indexed elements and named elements For example, for a file I uploaded while testing a PR, the output of print_r(getimagesize($filename)) is:

A very strange decision when designing the response of this function!

Index 2 is the file type which is an "IMAGETYPE" constant, such as IMAGETYPE_PNG. Note that there's also a constant called IMG_PNG, but this is a different number, so make sure you use the right one!

This is useful for file uploads. Consider this data in $_FILES:

In this case, there is no extension on the uploaded filename and the type is application/octet-stream. If I want to resize this image using gd, then I'm going to need to know whether to use imagejpeg, imagegif or imagepng. A simple way to do this is something like this:

It's easier than dealing with the type from $_FILES too and by writing it down, maybe I'll remember it.