Archive for the ‘PHP’ Category

You really can do bash completion with spaces!

April 28th, 2016 No comments

A short period ago when I was working on my little ec2ssh project I ran into the issue of tab completion not working for things with spaces in them.

This was my first foray into the world of bash completion, so I incorrectly thought "this can't be that hard - everything has completion now."

After Googling for hours, trying various things, finding statements saying that it wasn't possible - I stumbled upon the solution. It works properly and was surprisingly easy.

The compgen command typically works with spaces for the word separators. What I had to do was make sure the source data was separated by something else, such as a linebreak (\n) and then tell compgen that was the separator.

So this line before the compgen command was key:

local IFS=$'\n'

Next, the complete command still won't work without feeding it the -o filenames option. This seems to be critical, telling it to behave like we are dealing with filenames makes it work properly. Note that I couldn't even find the original example that led me to this solution right now. It's that undocumented.

complete -o filenames

If you'd like to see this put altogether, in a very easy to read, semi-documented autocomplete script, check it out here:

Categories: PHP

Custom XHProf run IDs

December 21st, 2014 No comments

XHProf is an awesome tool, but ships with a very annoying restriction out of the box. It names the run IDs in a cryptic randomized fashion (which makes sense - should be no collisions, and there's no "good" default way to name them otherwise.)

The good news however is that it does support custom run IDs to be named in the save_run() method. Awesome! Except for an odd "bug" or "feature" - a custom run ID won't display in the runs UI if it has non-hex characters in it (see the end of this post for information about that.)

This makes profiling specific requests a lot easier - you can put in a unique query string parameter and see it come up in the run ID, if the URL isn't already obvious. You could also simply define a standard query string parameter for your users/developers to use instead of the entire [scrubbed] URL as a run ID. Since I run a multi-tenant development server with a bunch of developers each having the ability to have a bunch of unique hostnames, it makes the most sense to use every piece of the URL for the run ID.

To start using custom XHProf run IDs, enable XHProf the standard way, at the earliest point in your application (at the top of the front-controller index.php, for example):

if (isset($_GET['xhprof']) && !empty($_SERVER['XHPROF_ROOT']) ) {
  include_once $_SERVER['XHPROF_ROOT'] . '/xhprof_lib/utils/xhprof_lib.php';
  include_once $_SERVER['XHPROF_ROOT']. '/xhprof_lib/utils/xhprof_runs.php';

The key to the custom naming is is when it saves the run output. In this example, I made a simple function to take the URL, remove all special characters and change them into dashes and remove any repetitive "dashing", and assign that as the third parameter to the save_runs() method, which is the "run ID" name.

if (isset($_GET['xhprof']) && !empty($_SERVER['XHPROF_ROOT'])) {
  function _make_xhprof_run_id() {
    if (isset($_SERVER['HTTPS'])) {
      $run_id = 'https-';
    else {
      $run_id = 'http-';
    $run_id .= urldecode($_SERVER['HTTP_HOST'] . '/' . $_SERVER['REQUEST_URI']) . '-' . microtime(TRUE);
    $run_id = trim(preg_replace('|([^A-Za-z0-9])|', '-', $run_id), '-');
    while (strstr($run_id, '--')) {
      $run_id = str_replace('--' , '-', $run_id);
    return $run_id;
  $xhprof_data = xhprof_disable();
  $xhprof_runs = new XHProfRuns_Default();
  $run_id = $xhprof_runs->save_run($xhprof_data, 'xhprof_testing', _make_xhprof_run_id()); 

If you wanted to use a simple query string parameter, I would still use the same type of safeguards so that the filename comes out in a sane way (no high ASCII or other characters which the filesystem wouldn't handle well) - for example, using the "run_id" parameter (I haven't tested this code, but it *should* work :))

if (isset($_GET['xhprof']) && !empty($_SERVER['XHPROF_ROOT'])) {
  function _make_xhprof_run_id() {
    // return null and it will handle it like usual
    if (!isset($_GET['run_id'])) {
      return null;
    $run_id = trim(preg_replace('|([^A-Za-z0-9])|', '-', urldecode($_GET['run_id']) . '-' . microtime(TRUE)), '-');
    while (strstr($run_id, '--')) {
      $run_id = str_replace('--' , '-', $run_id);
    return $run_id;
  $xhprof_data = xhprof_disable();
  $xhprof_runs = new XHProfRuns_Default();
  $run_id = $xhprof_runs->save_run($xhprof_data, 'xhprof_testing', _make_xhprof_run_id()); 

NOTE: Both of these methods require one thing to be fixed on the display side. Currently, the XHProf display UI that comes with the stock package *will* list all the XHProf runs, but won't load them if there's non-hex characters in the run ID. I don't know why this naming limitation is being forced. I've filed a bug[1] for now to ask why, or to propose removing the restriction (ideally) - however, for now I've commented out those three lines and everything seems to work fine so far.


Categories: PHP

PHP 5.4 stuff I'm jazzed about...

January 28th, 2012 No comments

I'm always excited to read updates to the NEWS file for each PHP version (yes, I am that big of a PHP fan boy) - and PHP 5.4 has quite a handful of noteworthy changes. I started cutting them out and decided to publish my "this is interesting" or "this is awesome" list...

This is as of PHP 5.4.0 RC6. Note that I didn't put in anything related to OO, as I despise the obsession with OO now in PHP and do my best to live without it.

Misc. notable changes:

  • Added built-in web server that is intended for testing purpose. (Moriyoshi)
  • Changed default value of "default_charset" php.ini option from ISO-8859-1 to UTF-8. (Rasmus)
  • Added array dereferencing support. (Felipe)
  • Added header_register_callback() which is invoked immediately prior to the sending of headers and after default headers have been added. (Scott)
  • Changed http_response_code() to be able to set a response code. (Kalle)
  • Added new json_encode() option JSON_PRETTY_PRINT. FR #44331. (Adam)
  • Changed silent conversion of array to string to produce a notice. (Patrick)
  • Removed support for putenv("TZ=..") for setting the timezone. (Derick)
  • Removed the timezone guessing algorithm in case the timezone isn't set with date.timezone or date_default_timezone_set(). Instead of a guessed timezone, "UTC" is now used instead. (Derick)
  • ext/mysql, mysqli and pdo_mysql now use mysqlnd by default. (Johannes) )I think this is in 5.3 though too?)
  • Expose session status via new function, session_status (FR #52982) (Arpad)
  • Added support for storing upload progress feedback in session data. (Arnaud)

PHP-FPM related:

  • Remove EXPERIMENTAL flag. (fat)
  • Added partial syslog support (on error_log only). FR #52052. (fat)
  • Lowered default value for Process Manager. FR #54098. (fat)
  • Enhance security by limiting access to user defined extensions. FR #55181. (fat)
  • Added process.max to control the number of process FPM can fork. FR #55166. (fat)
  • Dropped restriction of not setting the same value multiple times, the last one holds. (giovanni at giacobbi dot net, fat)

Removed legacy features:

  • Safe mode and all related ini options. (Kalle)
  • register_globals and register_long_arrays ini options. (Kalle)
  • import_request_variables(). (Kalle)
  • allow_call_time_pass_reference. (Pierrick)
  • Session bug compatibility mode (session.bug_compat_42 and session.bug_compat_warn ini options). (Kalle)
  • session_is_registered(), session_register() and session_unregister() functions. (Kalle)
  • y2k_compliance ini option. (Kalle)
  • Removed magic_quotes_gpc, magic_quotes_runtime and magic_quotes_sybase ini options. get_magic_quotes_gpc, get_magic_quotes_runtime are kept but always return false, set_magic_quotes_runtime raises an E_CORE_ERROR. (Pierrick, Pierre)
Categories: PHP, PHP-FPM

PHP.reboot - are you kidding me?

October 9th, 2011 No comments

Something just cropped up today on HN about a "reboot of PHP" - being a PHP fanboy, I decided to go look. I've had my own ideas on what I'd change (or rather, just clean up, optimize, and purge) from PHP.

The project is here:

Why is this an issue? Well, for one, it's NOT A REBOOT OF PHP. It's a frickin' Java-based re-implementation of some PHP ideas and function names with a completely different syntax, and at the end of the day, it has 99.9% nothing in common with PHP.

Why do people develop in PHP? Because it is PHP. Stop trying to make PHP more like Java, more JSON-y, etc. Why did it become the world's most popular language? Besides for being easy to pick up (too easy, sometimes, which leads to a bunch of garbage and unsecure code), it got there because of what it is.

This "php.reboot" project is just trying to use PHP's popularity and function names to get people to check it out. PHP doesn't have XML/JSON/SQL style constructs (although the new array syntax sure does look like an attempt to emulate JSON, cough), it has structure - that's what "$" and ";" are for - denoting specific constructs in the language. If people don't want to develop using "$" or ";" go switch to another language that doesn't, that is already established.

I am tired of seeing blog posts and other items pop up every so often "why PHP wants to be more like Java" or "10 things PHP can learn from Ruby" - if you're trying to adapt PHP to another language, just use the other language. Period.

Some of the ideas in this project might be neat, or good; but in the end, it's not a "reboot of PHP" and stop labeling it as one.

Categories: PHP

Poor man's Global Redirect for Drupal 6.x

March 22nd, 2011 No comments

I was moving a customer's site from an old HTML and individual PHP page site to a friendly URL site managed by Drupal, and I only cared about intercepting URLs with those file extensions. I installed Global Redirect on a Drupal 6.x site, and the entire site started going into an infinite redirect, before I even had time to configure it. I had to use Drush to disable the module, and immediately uninstalled Global Redirect since I didn't have time to debug what was going on, and hacked this up.

I didn't really need this to do much. The code is simple and there is no UI to manage it, but it works, and even gives you cute little X-Redirect headers to let you know if it was executed and if it found a match. It would be easy enough to take that if() out and have it check any URL (just be sure to remove the fallback :))

function foo_init() {
    if(stristr($_SERVER['REQUEST_URI'], '.php') || stristr($_SERVER['REQUEST_URI'], '.htm')) {
        $old = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        $new = db_result(db_query("SELECT new_url FROM custom_redirect WHERE old_url = '%s'", $old));
        if($new) {
            watchdog('foo', $old.' found in the custom_redirect table', NULL, WATCHDOG_INFO);
            header('X-Redirect: Found');
            drupal_goto('http://'.$_SERVER['HTTP_HOST'].$new, '', '', 301);
        } else {
            watchdog('foo', $old.' NOT found in the custom_redirect table', NULL, WATCHDOG_ERROR);
            header('X-Redirect: Not Found');
            drupal_goto('http://'.$_SERVER['HTTP_HOST'].'/', '', '', 302);

The table?

CREATE TABLE custom_redirect (
  old_url varchar(150) NOT NULL,
  new_url varchar(150) NOT NULL,
  PRIMARY KEY (old_url)

Enjoy. Totally could have Drupal'ed that up and made a hook_install() for the schema too, right? :p

Categories: Drupal, PHP

Setting PHP INI parameters from nginx

February 11th, 2011 No comments

A little known feature in PHP-FPM 5.3.3+ (since it was integrated into PHP core) is that you can actually define PHP INI parameters inside of your nginx configuration. This bridges some of the desire to have "php_value" and "php_admin_value" from Apache available. It's not user-override-able, but things like htscanner or newer PHP 5.3 features could address some of that.

This is cool, and I wasn't sure it actually got in a build or not, I remember it was mentioned or discussed, but sure enough, Jérôme coded it and got it in to FPM in core. So it is available to all, and he welcomes the feedback - see this thread on the nginx mailing list.

Due to limitations in the FastCGI protocol, you have to pass all the parameters you want as a single string, separated by "\n" - it's not the cleanest looking configuration, but that's how it is for now. I spitballed a different approach to it, but at the moment I believe it will be unlikely to get adopted.

If you're like me, you're probably looking for the code samples almost immediately. Here's your examples. Note that PHP_VALUE and PHP_ADMIN_VALUE are both legitimate keys, the difference being that PHP_ADMIN_VALUE does not allow the user to override the value using ini_set() - see the manual for more infomation.

Single value:

fastcgi_param PHP_VALUE;

Multiple values, manually line-broken:

fastcgi_param PHP_VALUE "

Multiple values, with the \n in there to clearly call it out:

fastcgi_param PHP_VALUE " \n precision=42";

More information is available in the feature request on the PHP bug tracker.

Categories: nginx, PHP, PHP-FPM

PHP 5.2.15 released, patch updated

December 9th, 2010 No comments

PHP 5.2.15 was released today, and I've made a copy of the previous patch. It still applies without any issues (a "make test" looks good) - this is supposed to be the latest version of PHP 5.2.x.

Download it here.

I highly recommend upgrading to PHP 5.3.3+ with the more updated/better FPM version (among a million other enhancements) that is bundled in core now. Coincidentally, PHP 5.3.4 came out today as well, with a handful of FPM bug fixes/features (see my other blog post or the NEWS file.)


Categories: PHP, PHP-FPM

I was wrong.

November 18th, 2010 No comments

I was wrong, and I'm happy to admit it.

I was worried that if FPM was to ever make it in to PHP core, it would stagnate and become part of such a big machine that it would take forever to receive updates. However, since its adoption into PHP 5.3.3, Jérôme has been hacking away on it and I was happy to see that in 5.3.4RC1, a handful of changes are being included:

  • Added '-p/--prefix' to php-fpm to use a custom prefix and run multiple instances. (fat)
  • Added custom process title for FPM. (fat)
  • Added '-t/--test' to php-fpm to check and validate FPM conf file. (fat)
  • Added statistics about listening socket queue length for FPM. (andrei dot nigmatulin at gmail dot com, fat)
  • Fixed inconsistent backlog default value (-1) in FPM on many systems. (fat)
  • Fixed bug #52674 (FPM Status page returns inconsistent Content-Type headers). (fat)
  • Fixed bug #52498 (libevent was not only linked to php-fpm). (fat)

Thanks guys, I am counting the days until I can finally use PHP 5.3. I also discovered the new magic variable __DIR__ exists a couple weeks ago - between everything, I am jonesing to move badly!

(For those wondering, "fat" is Jérôme's pseudonym.)

Categories: PHP, PHP-FPM

How would I change PHP?

September 22nd, 2010 3 comments

Anyone who knows me knows I am a PHP fanboy. I use PHP for everything - web applications, web scraping, batch scripting, if there is an itch that software can fix, I try to scratch it with PHP. I dreamed of a PHP scripting plugin for Eggdrop IRC bots, so I didn't have to fuss with TCL. Anywhere PHP could be adopted, I've hoped someone was working on a way it could be.

However, if you talk to people who know the internals of PHP they'll tell you there's a lot of ugly stuff in there. That it's a language based on macros, etc. I don't necessarily care about that. My experience is from a user perspective, not an internals one. That being said, just from my higher level interaction with the language, these are some of the things I'd love to change.

  • Make function name conventions consistent. Some functions have underscores, some don't. strpos vs. str_replace, html_entity_decode vs. htmlentities, etc.
  • Make argument order consistent for similar types of functions. Depending on what you're doing, it's one or the other. in_array($needle, $haystack) vs. strstr($haystack, $needle), etc.
  • Optimize the core. Strip the core down more, and push more things into modules. Enable some of them by default, fine. But when it comes down to it, I don't need easily 30-40% of the functions that PHP has built in.
  • Combine similar functions and use arguments to define the behavior. For example addslashes() and addcslashes(). Make it one function with a constant to define its behavior.
  • Disable magic quotes (preferred) or enable it and don't give any option to change it. As far as I'm concerned as long as you pick one route, you can guarantee universal compatibility, whether that means using magic quotes, or not using them and expecting developers to understand input sanitization, sanity checking/type checking/all that jazz. Which I don't think is a bad thing.
  • Implement a "strict" mode. "PHP is lazy" as Rasmus says which is fine and all, but I don't like the PHP name shamed with terms like "insecure" - any code can be insecure in any language, however, PHP is so easy to pick up and get things going that it makes it too easy to write crappy and insecure code. Specifics on a "strict mode"? I've got none. It's late and I can't think of how I would enforce better coding practices in core...
  • Get rid of $_REQUEST. I've advocated this for years and even unset($_REQUEST) in my code. To me it's a lazy person's workaround for coding and introduces some of the same vectors that were closed when disabling register_globals. If you -really- want to have a $_REQUEST type mechanism in your code, just array_merge($_GET, $_POST, $_COOKIE, etc) in whatever oder you want. I dislike using software that uses $_REQUEST by default but doesn't actually need the flexibility of POST vs. GET vs. COOKIE and such. Know which input stream your data is coming from, if nothing else, it will at least make replay attacks and such much harder for people to craft.
  • Get rid of objects and OO stuff. Yeah, I said it. Everyone loves OOP. Why? While I see the power of being able to extend classes, I also see it seeming to be the most troublesome when it comes to compatibility checks, all the APC crashing or odd bugs I've suffered from were due to it. If you look at something like Drupal, they've figured out how to extend or override using procedural code quite well. Sadly, even they're converting more things to OO as well.  IMO, OOP is more suited for longer-running applications, perhaps something event driven where a new object to represent a connection is created (however, C's been doing this without dealing with objects forever, it doesn't HAVE to be OO...) Those are the two main examples I see for using OO. Disclaimer: I wasn't raised in an OO environment, this is all based on personal experience and preference. 🙂

I've memorized the function list for what I use pretty well (like I said, I probably only use a subset of the functions in PHP) however the most annoying thing is when it comes to the needle vs. haystack argument positioning. I usually have to reference for it. Sometimes I can trial and error though. In an ideal world, I wouldn't have to.

It would be great if something like PHP 6.0 would adopt some of these practices, since it is a major version change. Perl, Ruby and Python I believe have all done similar things where a major change really was a dramatic change and required conversion of code to meet its new requirements.

I'm sure this list could grow, and I may add to it. Who knows.

Categories: Development, PHP

Cleanest configuration for the new PHP-FPM?

August 26th, 2010 9 comments

When examining the PHP-FPM configuration, I realized that I only tweak a few key pieces per pool, so I decided to share my approach to minimize redundancy and keep things simple (more files, but simpler to manage)

Because I still have to maintain PHP 5.2.x for clients, I have decided to try building everything in self-contained in an /opt/php53 directory. So consider that my $prefix, and change appropriately.

I have the following setup, and it seems to work great so far.


log_level = notice
error_log = /opt/php53/var/log/php-fpm.log
pid = /opt/php53/var/run/
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 5s
daemonize = yes

; pools
include = /opt/php53/etc/fpm.d/pools/*.conf

One file per pool, for example, a pool named "mike" -


listen =
user = mike
group = mike
request_slowlog_timeout = 5s
slowlog = /opt/php53/var/log/slowlog-mike.log
pm.max_children = 5
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 500
include = /opt/php53/etc/fpm.d/common.conf

Common elements for each pool (if these could be inherited globally, which they MIGHT be, I could just toss them in the main php-fpm.conf. Perhaps a feature request. Will post on the mailing list...)

Remember that rlimit_files needs to be something set in your sysctl.conf or on the system level or you'll get that RLIMIT_NOFILE warning. Also, depending on how you want to limit resources per pool/client, you may want to tweak things, such as request_terminate_timeout.


listen.backlog = -1
listen.allowed_clients =
pm = dynamic
pm.status_path = /status
ping.path = /ping
ping.response = pong
request_terminate_timeout = 120s
rlimit_files = 131072
rlimit_core = unlimited
catch_workers_output = yes
env[PATH] = /bin:/usr/bin:/usr/local/bin:/usr/local/sbin:/sbin:/usr/sbin:/opt/php53/bin:/opt/php53/sbin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

As always, YMMV.

Categories: PHP, PHP-FPM