Symfony Console Input Testing

If you’re writing a Symfony Console application, you’ll likely be getting user input via the Question helper. The Symfony manual has an entry on expected input. Unfortunately until they update the docs (github issue #5246) with a better example, it creates brittle test cases that fail spectacularly, sitting in the middle of a PHPUnit run expecting user input. Which would ruin your whole test run when running in travis-ci or jenkins.

Thankfully there is a better way, which is to mock the question helper ask method. I’ve provided the ofbeaton/console-tester package on packagist so you can use it in your project.

Continue reading Symfony Console Input Testing

nginx pretty url rewrite

Sometimes things just don’t work like they should. So it was with url rewriting using nginx 1.6 and php 5.6 through fastcgi for me, using a Symfony 2.3 project. The examples out there use all kinds of different techniques that make all kinds of assumptions.

The file I’m looking at is /etc/nginx/conf.d/ssl.conf for https and /etc/nginx/conf.d/default.conf for http. You’ll probably have fastcgi enabled (I did through php56w-fpm from webtatic on centos) and if you want nice urls like https://yourhost/yourapp/cool-link-to-this you’ll need to do some pretty url rewrite.

There are a LOT of ways of doing it, here’s what worked for me, a combination I had trouble finding online.

In the server block you’ll have your fastcgi php config, something like:
location ~ .php$ {
try_files $uri=404
}

If yours isn’t exactly like this, don’t worry, the important part is the location line. Don’t change it, just make note of it. If it’s .php$ like mine is, then this mean the last part of the URL has to end with .php or it won’t be treated as a php script. So /yourapp/app.php?blah works but /yourapp/app.php/blah does not. This is important in what rewrite rules will work for you.

If you had something like:
location ~ .php(/|$) {
Then urls like /yourapp/app.php/blah may work, but I have a feeling this is a little less secure. Notice that changing this block didn’t solve my problems, so I opted to leave it with the stricter .php$ on my server.

After this block I added my rewrite rule for my application.
location /myapp/ {
index app.php
try_files $uri $uri/ @rewriteapp;
}

location @rewriteapp {
rewrite ^/myapp(/.*)?$ /myapp/app.php?$1 last;
}

A bunch of stuff is happening here, and you’ll need a set of these for every app you want pretty urls. You could make the location just / for the root of your domain, but mine was in a subdirectory.

The first thing is that I have a trailing slash on /myapp/ in the first location block. I don’t know if this is important, but that’s how the nginx documentation lists it so that’s what I did too.

Next, the index app.php tells it that my default index is not index.php but app.php. This is because I’m using the Symfony php framework, and it uses app.php for production and app_dev.php for development. Change it to what you use in your project.

This next line was different in a lot of places on the internet. I’m not convinced I need to use the @rewriteapp convention, that I could put the destination php script right there, but I don’t have a working example of that and the @location was popular when I did my googling.

You’ll want to make sure you have both $uri and $uri/ on the try_files line, in case the user forgets to put a trailing slash, this makes /myapp and /myapp/ both work. The @rewriteapp must be a unique name, so change it for each app you make. That passes processing if it can’t match to an existing file or directory.

In the @rewriteapp section, I had to tweak things as well. The first part says to match anything with /myapp at the start of the url, with any amount of stuff following it. The next part says what to rewrite it to, in this case the specific url where the php file is exposed from the web, app.php. Notice I used a ? in app.php?$1 here, some examples use a slash, app.php/$1 but that won’t work if your fastcgi config is like mine was far above. Lastly the ‘last’ says not to process any more rules. Some people have ‘permanent’ here but that’s not correct and will lead to problems if you change your url scheme.

I don’t really know the innards of what is going on or why everything is working, but this is what I had to do to get it working, and it was different to the other answers online. So try mine, then try theirs, and if none of them work but you figure it out write your own article!

Don’t forget to be awesome.

pthreads using php+zts rpms on centos

UPDATE: To make it work with PHP 7.1, you will need to download the latest master branch from pthread’s github¬†instead of PECL.

I recently had to take an old project from several years ago out of our SVN archives, it is a PHP CLI that uses the pthreads extension to do a bunch of work in parallel. It also abuses set_time_limit() to get around the fact that some other extensions and library functions in PHP fail to provide a way to set timeouts, allowing the parent thread to manage them.

No problem, I’ll just install pthreads again on my current rpm distribution of PHP 5.6 install on centos 6.5.

# pecl install pthreads
WARNING: channel "pecl.php.net" has updated its protocols, use "pecl channel-update pecl.php.net" to update
downloading pthreads-2.0.10.tgz ...
Starting to download pthreads-2.0.10.tgz (85,247 bytes)
....................done: 85,247 bytes
36 source files, building
running: phpize
Configuring for:
PHP Api Version: 20131106
Zend Module Api No: 20131226
Zend Extension Api No: 220131226
building in /var/tmp/pear-build-rootc3k10v/pthreads-2.0.10
running: /var/tmp/pthreads/configure
.
.
.
checking whether to enable Threading API... yes, shared
checking whether to enable pedantic locking... no
checking checking for ZTS... configure: error: pthreads requires ZTS, please re-compile PHP with ZTS enabled

No problem, I’ll just install zts. A quick yum install php56w-zts reveals there isn’t such a package in my repos.

My organization has been using Andy‘s fantastic webtatic php releases for several years. Sure enough checking his repo and I can’t find a recent zts repo, more googling reveals that with 5.5.1 zts is now rolled into the main rpm. Great, so I should have it right? Let’s just check what’s installed.

# php<tab>
php php-cgi php-config phpize
# ls /etc/php<tab>
php.d/ php.ini php.ini.rpmnew php.ini.rpmsave php-zts.d/
# ls /usr/lib64/php<tab>
php/ php-zts/

So clearly I have some kind of zts branch installed, but webtatic’s php 5.6 page only mentions using zts with apache’s libphp5.so. Not with the php or php-cgi executables. At this point I did some more googling, but every post out there indicated I would have to build php myself. I absolutely did not want to do this, it would be hell for releasing this code to our many web servers, for one. I started to look into converting the code to pcntl which would work out of the box with my php cli.

But first a quick tweet @andytson and he’d get back to me a few hours later with what I was missing.

Aha! I can still use pthreads! I’m not really comfortable digging into the contents of rpm’s, so I’m honestly not sure I would have ever found this. It’s not documented anywhere nor does it follow the conventions set above. Why this one is zts-php and not php-zts is beyond me. Note that it’s in the php56w-devel package, but I already had this installed on my system.

# zts-php<tab>
zts-php zts-php-config zts-phpize

Andy even went a cut above and tweeted again to provide me the info I would need to build the pthreads extension, warning me there is no zts-pecl provided. This I could work with, thanks Andy!

# cd /tmp
# pecl download pthreads
# tar zxvf pthreads-2.0.10.tgz
# cd pthreads-2.0.10
# zts-phpize
# ./configure --with-php-config=/usr/bin/zts-php-config
# make

And I was the new owner of a pthreads.so. You may need to yum install automake and autoconf to get the ‘configure’ and ‘make’ commands on your system, as well as some other -devel libraries. To put it into the general structure, I had to do a bit of copying.

# cp modules/pthreads.so /usr/lib64/php-zts/modules/.
nano /etc/php-zts.d/pthreads.ini
extension=pthreads.so

And I was rolling. To double check everything was running properly I ran a grep on phpinfo.

# zts-php -i | grep -i thread
/etc/php-zts.d/pthreads.ini
Thread Safety => enabled
pthreads

Notice the Thread Safety line shows enabled, without ZTS it will be disabled. The pthreads line tells me my extension was properly loaded. I changed my cron job to execute zts-php instead of php and my project was working with pthreads again!

Please note that you’ll have to recompile pthreads each time you download a new version from webtatic, as Andy does not yet provide a php56w-pthreads rpm. Here’s to hoping!

I’m a big fan of the webtatic rpms as they have saved me hours of work, and have been more stable then remi and newer than centos or epel. If you find his packages useful I encourage you to click his donate button on the webtatic page to support his efforts.