Well that’s 8GB I didn’t have before

Adobe CS4 Uninstall

Preview is better than Acrobat for my PDF needs (specifically annotations).

Pixelmator handles my current image editing needs just fine. I never found CS4 lacking in features, and Pixelmator has all the features I used, and they’re at least good enough that I can’t tell the difference in quality.

Both open faster and have a smaller memory footprint than the Adobe equivalents.

Advertisements

Mermaid Ave, Vol 3

The latest in the Mermaid Ave series is fantastic.  Sounds like it was made to be listened to on vinyl, although that’s a bit biased since I haven’t heard this one on CD. But listening to them all in succession on vinyl, they get progressively better.  The songs are much better than Vol 2 — I like the Vol 1 songs best, and this is equal in songwriting quality.  It’s still more of the same, so if you didn’t like either of the others, there’s nothing here to change your mind. This will likely be the first Mermaid Ave album I grab when I want to put some on, unless it’s to hear some specific songs on Vol 1.

Mermaid Ave, Vol 1

Sounds like it was mixed and mastered with digital in mind. Not sure how I can explain that, other than: there’s nothing special about this album on vinyl.  Guy at the record store said “it’s got that 90s production feel”, and I’m sure that’s part of what he meant.  The songs are as awesome as ever. If I had bought it on its own I would have been a bit disappointed, but the other volumes are great on vinyl, so it’s nice to have the whole set.

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.

Google News considerations

You’ll notice a few of these suggestions either aren’t practical, or conflict with other suggestions. You’ll also notice the supporting documentation is for fixing errors with Google News listings. We have noticed that adhering to these when possible produces good results, so that’s why I’m calling attention to them.

Images

http://support.google.com/news/publisher/bin/answer.py?hl=en&answer=13369

  • Make sure that your images are fairly large in size, at least 60 pixels by 60 pixels. (only applies to main article image)
  • Use images that have reasonable aspect ratios.
  • Ensure that your images are inline.
  • Ensure that your clickable images link to a URL with a .jpg or .jpeg extension.
  • Place your images near their respective article titles.
  • Label your images with well-written captions.

Article snippets

http://support.google.com/news/publisher/bin/answer.py?hl=en&answer=70752&topic=2523198&ctx=topic

  • To give users a preview of an article before clicking on it, Google News displays its first few sentences on our homepage and in search results. To determine which text to include, our crawler looks at each article’s code for body text near the headline of that article.
  • We also recommend clearly differentiating the text that makes up your articles’ author bylines and date information from the text of your articles’ first sentences. Ideally, we will only show the first few sentences of your articles under their headlines in Google News.

Article date

http://support.google.com/news/publisher/bin/answer.py?hl=en&answer=70871&topic=2523198&ctx=topic

  • Place a clear date and time for each of your articles in between the article’s title and the article’s text in a separate line of HTML. This should help our crawler correctly identify the publication date for your article.
  • Make sure to provide us with the date when the article first appeared on your site.

General

Just putting it here for reference.

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' );

Integrating InAppSettingsKit with Storyboard, UITabBarController, and ARC

I love the concept of InAppSettingsKit.  While it’s possible to make your own settings view and hook up all your own buttons, I like the simplicity of installing a “plugin” — just copy over the files, hook it up to a view, and be done with it.

I’m using the iOS 5 SDK with a Storyboarded app, using a Tab Bar, and I was able to integrate it pretty simply after a trip to Google got me on the right track:

1) Created my Settings.bundle, including NSUserDefaultsDidChangeNotification observers as described in the Apple Settings bundle documentation.  The AppPrefs sample app helped here (specifically with the observers).

2) Copied the InAppSettingsKit directories (not the sample app) into my project.

3) Made sure I had all the necessary Apple frameworks:

  • MessageUI Framework
  • UIKit Framework
  • CoreGraphics Framework
  • Foundation Framework

MessageUI was the only one I needed to add.  Project > Targets > MyApp > Build Phases > Link Binary With Libraries and click the + icon to add any that are missing.

Before adding it, I was getting this horrible error:

missing required architecture i386 in file
Undefined symbols:
  "_OBJC_CLASS_$_MFMailComposeViewController"

The nature of the error message was completely alien to me, but — again — thank you, Internet.

4) In Storyboard editor, I added a new Navigation Controller and Table View Controller.
4a) I deleted the view controller that came along for the ride when I dragged the new navigation controller to my storyboard.
4b) I linked the navigation controller to my tab bar controller, then linked the navigation controller to the table view controller (control+click and drag).
4c) I selected the Table View in the table view controller and changed the Style of the prototype content to “Grouped”.
4d) I changed the controller class to IASKAppSettingsViewController.

Et voila, it compiled and worked. With this method I didn’t need to add any custom controllers or views; just the InAppSettingsKit files and linked a new table view to the main IASK controller.

Also worth noting: since I’m using ARC in my project, I opted for an ARC-compatible fork of InAppSettingsKit. See the ticket on Github. I used tibr’s fork.

Related: