Tag Archives: php

10 reasons why WordPress is a better starting point for a project than you thought, even though you’re an advanced PHP developer

I didn’t quite mean to make this a “top 10” list, but it did work out to 10 items, and it’s indeed a list.

UPDATE: I didn’t make a few points clear originally, so let me add some context here.

The impetus for writing this post was of 3 weekend projects that never got off the ground because I got bogged down with the setup. I was familiar with the framework I was using, it gave me all the tools I needed to get the project going, and as I started building my functionality I started realizing I needed X, Y and Z to keep going. So I grabbed packages (some I was familiar with, others less so, but all were modular and would fit right in with the framework I was using) and spent a bunch more time getting them connected and playing nice with each other, realizing I needed to modify my database schema to support certain features from those packages, etc.

By the middle of weekend #2 I still hadn’t really started coding what I wanted to work on. During the following week I had a bit of an epiphany that everything I’d spent a bunch of time doing to get my project started using simple, existing modular components that were easy to plug in and use already existed within WordPress. At the start of weekend #3, I started fresh with a WordPress install and just started coding the thing I wanted. I just never realized how much time I spent wrangling modules and components before.

Google App Engine provided a similar feeling. At the time I started playing with App Engine it didn’t support PHP, so I used Python, and I was able to just start coding. Users, permissions, access, etc, were all taken care of. The only thing I was mildly annoyed with was that I couldn’t find any existing themes, but it wasn’t too time consuming to grab a WordPress theme and make it work with Jinja2. Having to define my routes was a little annoying / time consuming too. I realized that WordPress would have made even those two things inconsequential, but they weren’t burdensome. But I digress.

Any CMS or Framework can do most of this stuff. The point isn’t that only WordPress does it, nor is WordPress necessarily the best at it. The point is just that WordPress already has these building blocks in place so when you just want to get your idea out there, there’s a bunch of stuff you just don’t have to deal with.

  1. User management and roles.  Has a fully functional user system available, and easy to hook into or customize.  So much better than rolling your own.
  2. Database structure and abstraction/access.  Fully functional database abstraction layer, and supports custom data types (just imagine custom post types are your default storage engine, not “posts”; and custom taxonomies are your relationships).
  3. Control/Admin panel.  WordPress has an admin panel “for free”. Easy to add pages, customize who can see what, etc.  This includes a fully-customizable user experience and WYSIWYG editor already present, which can be easily attached to anything.
  4. HTTP client.  WordPress has a pretty smart HTTP client, and can handle a lot of situations (mostly encountered by shared hosts).  It’s no Guzzle but it’s very reliable, and functions as expected under most normal circumstances.  It even allows non-blocking requests (these are asynchronous but may still trigger handlers on failure/success, just not in the same process or request).
  5. Scheduled tasks.  WP Cron leaves a lot to be desired, but it’s there, and it (mostly) works, and having even a half-assed solution pre-built beats building your own half-assed solution that you’ll never get around to finishing.
  6. Cache client.  With automated fallback if no persistent cache is available.
  7. Route management / pretty URLs / SEO URLs are already present, and works by default when implementing custom pages, post types, taxonomies, and kind of archive or detail page..
  8. Pretty much everything has an observer pattern built-in.
  9. Search.  Like scheduled tasks / cron, WordPress search kind of sucks out of the box, but it’s there, and plugins (+ the observer pattern for searches) are available to allow you to search using any kind of actual search engine you want. But again, it’s at least got a “good enough” search already available until you implement an improvement.
  10. It’s “legacy” code, and ugly, but that doesn’t mean your code has to be.  There’s nothing to stop you from writing modern PHP code for your classes and themes.  (Except that WordPress can be a little weird about namespaces, due to the way the observer pattern is implemented.)   Incidentally, it’s improving.  Thing is, these are things you just have to deal with when your software has millions of users and requires backwards compatibility, and also so that your software can reach hundreds of millions of users in the first place.

What I wish I knew about writing PHP and web apps when I started

Chris Cornutt (@enygma) asked on Twitter, “If you were just starting to learn about writing secure PHP apps, what would you want to know?”  While I replied via Twitter, I figured I’d post my own short list here. I’d certainly consider this a beginner’s list, but it’s the kind of basic stuff I wish I had known.

  • There’s nothing inherently secure about POST requests nor data retrieved from the $_POST superglobal. POST parameters are sent within the body of the message instead of the URL, which allows for longer key/value pairs than using a querystring, but it’s just as visible as any GET parameter.
  • Anything transmitted to/from the server is inherently readable by anybody unless you specifically take precautions, such as transmitting via HTTPS.
  • There’s no automatic/magic security or sanitization built in to most standard PHP functions nor frameworks. It’s often there, but you have to consciously use it.
  • Just because it looks like an image, responds like an image, doesn’t mean it’s an image. (Or other type of included file.)
  • 3rd party resources have access to anything on the page, regardless whether it’s visible, behind HTTPS, or obfuscated. Serving your site via SSL isn’t a magic bullet. Javscript can still access elements on the page and do nasty stuff (XSS), and you’re still vulnerable to CSRF attacks.
  • Just because something is only “visible” server-side doesn’t mean it’s inherently secure. For example, any variable can be made global, and all the data within it can be read by any PHP script or method within that script. Case in point: the widely-used Akismet plugin for WordPress includes a dump of $_SERVER in each spam check it makes. This isn’t specifically a problem with Akismet, it’s just illustrating that code can be exposing stuff you didn’t think about, and may be exposing things you didn’t realize. You can do some really evil stuff.
  • Just because you got a file from a reputable source, doesn’t mean it’s safe or good.

Some of those are web security but I didn’t know I needed to care when I started doing PHP  and web development.  I shudder to think of some of the code I wrote that’s still out there.

Related links

Aside: One of the reasons I love WordPress is that it gives you all the tools to write secure code out-of-the-box.  Other Frameworks like Zend and Symfony do, too, but they’re not as obivous.

Debugging WordPress: Find Slow Filters and Actions

English: WordPress Logo

This is one of the ways I diagnose performance issues within WordPress, specifically “hey this site is slow, what can we do to speed it up?”  Whereas a callgrind file gives you a look into the whole callstack of your script, the point of this is to profile actions and filters in WordPress.

It does require that you make some changes to core files.  This is not meant to be something that you use in production, nor is it meant to be something you run all the time.  This is for “spring cleaning” your site, and/or tracking down general slowness.

The code between “// @custom start” and “// @custom end” is what you will be adding.  I am not including line numbers because they change frequently with the version of WordPress.

“But wait”, you say, “Just add the profiling to the ‘all’ filter and you don’t have to do all this.”  That’s probably fine for most cases.  This method measures actions and filters that execute before plugins are loaded.  Additionally, there’s always the chance of a priority conflict even if you put priority 0, because if there are multiple items at the same priority level they just get appended to the list, so your profiling hook may execute after another action/filter.

So without further ado:

index.php

Put this at the top of index.php, before any other code.

class Pmc_Debug
{
    protected static $_threshold_to_hide = 0.1;

    public static function get_threshold_to_hide() {
        return static::$_threshold_to_hide;
    }

    public static function set_threshold_to_hide( $time ) {
        static::$_threshold_to_hide = (float) $time;
    }

    public static function record_action( $name ) {
        $backtrace = debug_backtrace(false);
        if ( ! isset($backtrace[2]['args']) ) {
             return;
        }

        foreach ( $backtrace[2]['args'] as &$arg ) {
            $arg = ( is_string($arg) ) ? stripslashes($arg) : $arg;
        }
        $GLOBALS['pmc_action_timer'][microtime()][] = array(
            'name' => $name,
            'backtrace' => var_export($backtrace[2], true),
        );
    }

    public static function print_recorded_actions() {
        ?>
        <hr />
        <div style="padding: 10px; background-color: white; color: black; white-space: pre; text-align: left;">
        <pre>
        <?php
        $timetotals = array();
        $break = '<hr />';
        $eol = '<br />';
        $detail_list = $eol . $eol . $break . $eol . $eol;
        $detail_list .= 'Detail action list.' . $eol;
        if ( static::get_threshold_to_hide() > 0.0 ) {
            $detail_list .= 'Hiding items faster than ' . static::get_threshold_to_hide() . ' seconds.' . $eol;
        }
        $detail_list .= $eol . $break . $eol;

        reset($GLOBALS['pmc_action_timer']);
        $previous_item = array('timestamp' => array('sec' => 0.0, 'usec' => 0.0), 'items' => array());
        do {
            if ( ! isset( $timestamp ) ) {
                $timestamp = microtime();
            }
            if ( ! isset( $items ) ) {
                $items = array();
            }

            list($usec, $sec) = explode(" ", $timestamp);
            $sec = (float) $sec;
            $usec = (float) $usec;
            $timestamp_float = $sec + $usec;

            if ( $timestamp && ! isset($start_time) ) {
                $start_time = $timestamp_float;
            } else {
                $end_time = $timestamp_float;
            }

            if ( empty($previous_items['items']) ) {
                $diff = 0.0;
                $previous_items['items'][] = array('name' => 'nothing', 'backtrace' => '');
            } else {
                $diff = $timestamp_float - ( $previous_items['timestamp']['sec'] + $previous_items['timestamp']['usec'] );
            }

            if ( $diff > static::get_threshold_to_hide() ) {
                $previous = array();
                if ( ! empty($previous_items['items']) ) {
                    foreach ( $previous_items['items'] as $previous_item ) {
                        $previous[] = $previous_item['name'];
                    }
                }
                foreach ( $items as $item ) {
                    $detail_list .= $eol . round($diff, 3) . ' seconds between starting ' . implode(', ', $previous) . ' and starting ' . $item['name'] . $eol;
                    if ( ! empty($previous_items['items']) ) {
                        foreach ( $previous_items['items'] as $previous_item ) {
                            $detail_list .= $previous_item['backtrace'] . $eol;
                        }
                    }
                    $detail_list .= $item['backtrace'] . $eol;
                }
            }
            foreach ( $items as $key => $item ) {
                $timetotals[$item['name']][] = $diff;
            }

            $previous_items['timestamp']['sec'] = $sec;
            $previous_items['timestamp']['usec'] = $usec;
            $previous_items['items'] = $items;
        } while ( list($timestamp, $items) = each($GLOBALS['pmc_action_timer']) );
        $detail_list .= $eol . $break . $eol;

        $summary_list = $eol . $eol . $break . $eol . $eol;
        $summary_list .= 'Action overview: aggregate totals.' . $eol;
        if ( static::get_threshold_to_hide() > 0.0 ) {
            $summary_list .= 'Hiding items faster than ' . static::get_threshold_to_hide() . ' seconds.' . $eol;
        }
        $summary_list .= $eol . $break . $eol;

        do {
            $total_time = 0.0;
            if ( isset($times) ) {
                foreach ( $times as $time ) {
                    $total_time += $time;
                }
            }
            if ( $total_time > static::get_threshold_to_hide() ) {
                $summary_list .= $tag . ' took approximately ' . round($total_time, 3) . ' seconds' . $eol;
            }
        } while ( list($tag, $times) = each($timetotals) );
        $summary_list .= $eol . $break . $eol;
        if ( $end_time < $start_time ) {
            $end_time = $start_time;
        }
        echo 'Request took ' . ( $end_time - $start_time ) . ' seconds from start to finish.' . $eol;
        echo $summary_list;
        echo $detail_list;
        ?>
        </pre>
        </div>
        <?php
    }
}

Pmc_Debug::record_action('bootup');

wp-includes/plugin.php

In this file, look for the functions below and add the lines between “@custom start” and “@custom end”.  Basically, they go at the top of all the functions where filters are applied and actions are called.

function do_action($tag, $arg = '') {
   global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
   // @custom start
   Pmc_Debug::record_action($tag);
   // @custom end 

function do_action_ref_array($tag, $args) {
   global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
   // @custom start
   Pmc_Debug::record_action($tag);
   // @custom end 

function apply_filters($tag, $value) {
   global $wp_filter, $merged_filters, $wp_current_filter;
   // @custom start
   Pmc_Debug::record_action($tag);
   // @custom end 

function apply_filters_ref_array($tag, $args) {
   global $wp_filter, $merged_filters, $wp_current_filter;
   // @custom start
   Pmc_Debug::record_action($tag);
   // @custom end

wp-content/themes/my-theme/footer.php

Here is the code that outputs the results.  This goes anywhere after the wp_footer() function, but it’s easiest just to put it before the closing </html> tag.

Pmc_Debug::record_action('done');
Pmc_Debug::print_recorded_actions();

Find yourself constantly battling browser cache when developing a script in WordPress?

This snippet will always give you a fresh copy of all the scripts and styles loaded via wp_enqueue_script() and wp_enqueue_style():

function pmc_dev_cachebuster( $src ) {
	return add_query_arg( 'ver', time(), $src );
}
add_filter( 'style_loader_src', 'pmc_dev_cachebuster' );
add_filter( 'script_loader_src', 'pmc_dev_cachebuster' );

Implementing New Relic Real User Monitoring in Magento

A few months ago, New Relic introduced Real User Monitoring.  It natively supports WordPress and Drupal as of the time of this writing.  By “natively supports”, I mean you can just turn it on in the New Relic control panel and your web servers will start automatically injecting it into your pages’ head.  Real User Monitoring works with any web app, however — you just have to manually add the code yourself.

Here’s how you add it to a Magento theme template. Continue reading Implementing New Relic Real User Monitoring in Magento

New Relic and Magento: Better Transaction Naming

New Relic supports Zend Framework out of the box.  Right?  Supposedly it does, but I didn’t get any useful information recorded when using Magento.  Everything came up “index.php”.

Unfortunately, getting a useful transaction name in New Relic from Magento requires modifying Magento core.  Fortunately, it’s a pretty simple modification.

Continue reading New Relic and Magento: Better Transaction Naming

How to add a Google Checkout button to any page in Magento

Image representing Magento as depicted in Crun...
Image via CrunchBase

This post answers a very simple question I had, one I could not find an answer for.  I needed to add additional Google Checkout buttons to Magento‘s onepage checkout and maybe the sidebar cart.  I found other people asking the same thing, and answers ranged from cryptic to unhelpful.  But I did find a solution.

Step 1

Add this snippet to the template file where you want the Google Checkout button to appear:

getLayout()->createBlock('googlecheckout/link')->setTemplate('googlecheckout/link.phtml')->toHtml(); ?>

This uses the standard Google Checkout button that’s used everywhere else, so if you customize the way the GCO button looks using the googlecheckout/link.phtml file your changes will show up everywhere you use it.  This is great because it reduces the duplication of code.  But what if you want to use a slightly modified GCO button somewhere? Read on…

web start script

Starting and stopping NginX / MySQL / PHP-FPM on Mac OS X

Keeping up with my local dev environment, a while back I wrote a post on Starting and stopping NginX-MySQL-PHP-FCGI on Mac OS X.  I’ve made some changes since then, and I now use a slightly different stack.

I modified MacPorts to configure PHP5 with FPM support, and added in Memcached (also Varnish, but we don’t use that at work and I haven’t been inclined to mess with it, so it’s not in my script).
Script source and changelog after the break…