Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How It Works

  • Defines, Variables, and Plugin Dirs

    Defines, Variables, and Plugin Dirs

    If you’ve spent any time looking at PHP code, then you’ve seen defines and variables

    Defines

    A define looks like this:

    define('SOMETHING', true);
    

    This makes a global constant that can be used anywhere. In the case of WordPress, it means they can be used across multiple plugins or themes. This is very useful if you make a suite of plugins that all have the possibility of using the same API key. Then you can tell a user to put define('MY_PLUGIN_API', '123456'); in their wp-config.php file, and tell your code to check for the define.

    A define also cannot be redefined. If you call it twice, you get errors, so you should be as unique as possible when creating yours.

    Variables

    A variable, meanwhile, looks like this:

    $SOMETHING = true;
    

    Variables only exist where they are, so if I have one in one function, I may not be able to call it in another. You can make global variables if needed, and in fact if you don’t, the variable won’t be available to all functions.

    Which Should I Use?

    Keeping in mind that defines are constants and variables are, well, variables, the idea is that a constant should be used for things that should not change in the running of the code. It also makes your code easier to maintain if the things that must be constant are explicitly so.

    So what’s a good define? Actually not really this:

    define('MY_PLUGIN_VERSION', '1.0');
    

    This is a constant, it’s something you should be setting and it shouldn’t be overwritten, but actually I’d want to make it a database field to check on before upgrading. Remember, you should be changing that define on upgrade, so having it be a declared constant is a little odd. Now that said, it is a good one when you consider you don’t want someone to willy-nilly override it. Except … what if you do? What if you want someone to be able to change it back to re-run an upgrade?

    So then really not this either:

    define( 'MY_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
    define( 'MY_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
    include( MY_PLUGIN_PATH . 'lib/asset.php') ;
    

    Someone’s probably thinking that their plugin directory is a constant and, thus, should be defined like that. Maybe, but it’s a pointless define in WordPress. You already have plugins_url() (which this example isn’t using) but it’s really where people use that code that makes no sense. That’s why I included the second line there. That’s what they use it for, and it means two lines of code for one function call.

    This actually magically becomes a good define when you have a complex plugin with multiple files and you need to grab the main plugin directory in sub-files. But if your plugin is one file (and yes, that’s where I see it the most), it’s overkill.

    This is a good define:

    define('MY_PLUGIN_APIKEY', '123456');
    

    But that should never be in your code itself. Not for WordPress at least. That should be in the wp-config.php, like I mentioned before.

    Basically … there aren’t great reasons to use defines unless you want things that never change. define('MY_PLUGIN_SUPPORT_HOME','http://help.example.com'); would make sense to me, as would other contact info you want to make sure is never subverted.

    What do you think define is best for?

    I’m interested to hear what you guys like to use defines for. I’m certainly guilty of using them for some pretty silly reason.

  • March into CloudFlare

    March into CloudFlare

    “Eating your own dogfood” is a colloquialism that describes a company using its own products or services for its internal operations. Microsoft supposedly invented it in the 1980s.

    DreamHost is partners with CloudFlare. I’ve tried time and again but I get hung up when we start talking about the delay in caching and the proxying of caches. Still, I know me. I can do things better and provide better support if I use a thing. I’m so good with PageSpeed and wp-cli now because I use them regularly.

    So it was time to knuckle down and use it for more than just a week. I was committing to a month on CloudFlare!

    Pick One Domain

    I decided to only do this for one domain. My busiest, and not a multisite, because I wanted to create a ‘real user experience.’ I didn’t use my company account. I made a new CloudFlare account, added this domain, and started there. I didn’t want Multisite because that’s where my store is, and if I screw up the busy site, I don’t lose money or risk people’s information. While I’m sure it can be used safely, I knew I was going to experiment a little, so I wanted to protect myself and them

    Turn on CloudFlare, Turn off PageSpeed

    You heard me. I turned PageSpeed off for the domain I’m testing on. I love PageSpeed, but after talking to some people, I’ve been wondering about how well it handles things. Also with SPDY and HTTP/2, compressing HTML is less and less of a concern. I wasn’t sure if there was a benefit to having everything be filtered and compressed before it loaded. Was I making the experience worse? After making sure I still had mod_cloudflare active and up to date, I used .htaccess to turn off PageSpeed.

    Break Your Code Flow

    I need to point out that CloudFlare warns you about this one. They tell you that if you need to SSH, you should use a different record or the IP. That wasn’t a big deal. I’d kept ftp.example.com separate for FTP anyway. All I had to do was change my SSH aliases to point there as well.

    I forgot that I use Git on my own server. I wanted to update a script and Coda hung. It took my brain a moment to remember that I was using Git with SSH so I had to remember how to change the remotes on Git:

    $ git remote -v
    # origin  me@example.com:USERNAME/REPOSITORY.git (fetch)
    # origin  me@example.com:USERNAME/REPOSITORY.git (push)
    

    This was a problem. My example.com main domain hit CloudFlare. So I had to change that to use ftp.example.com as well. That wasn’t too hard, just running this 6 times.

     $ git remote set-url origin me@ftp.example.com:USERNAME/REPOSITORY.git
     $ git remote -v
     # origin  me@ftp.example.com:USERNAME/REPOSITORY.git (fetch)
     # origin  me@ftp.example.com:USERNAME/REPOSITORY.git (push)
    

    Still, I felt pretty silly!

    Break Your Email

    Same song, second verse. I had to add in a CNAME for smtp.exmaple.com on CloudFlare because I use that to send emails and I use mail.example.com to receive. By default they know mail should be ignored. The scan didn’t pick up smtp. I forgot about it until I tried to reply to an email.

    Break Your Tools

    Not the ones on my computer. My other CMSs broke. CloudFlare is used to WordPress, and has Five Easy First Steps to using WordPress and CloudFlare.

    In that document, they specify this:

    Create a Page Rule to exclude the wp-admin or wp-login sections from CloudFlare’s caching and performance features. You can access PageRules in your CloudFlare ‘Settings’ options.

    e.g.

    *example.com/wp-admin/*
    *example.com/wp-login/*
    

    Why do this?

    While there is not always an issue, we have seen instances where optional performance features like Rocket Loader may inadvertently break certain functions (editors, etc.) in your WordPress back end.

    Except there are major problems (besides the fact that the second example should be *example.com/wp-login* without the trailing slash)! The free version only gives you three rules. I’m using four apps (WordPress, ZenPhoto20, Yourls, and MediaWiki). That means if I need to white list all of them, I’m out of luck.

    Then there’s the problem that *.example.com matches blog.example.com and www.example.com but does not match example.com and guess what? I’m using example.com without the WWW. I hate WWW. And yes, you can use a naked domain with CloudFlare.

    Break The Site (For One Person)

    Someone pinged me to let me know the site was down in Scotland:

    Website is Offline Message from CloudFlare

    It wasn’t in Manchester or Dublin. It wasn’t in the US. It wasn’t in Canada. I opened a support ticket after making sure that it wasn’t really me. The server was up (all other sites, including this one were up) and I could get the site via anonymous proxies. Only that user had an issue, and I was 100% positive I had whitelisted everything in CSF (it’s the same thing I do for Jetpack). But the website claims a 522 is my server.

    This was never resolved, and demonstrates a major issue in the process. The user was a non-web savvy user. She shouldn’t have to be, though. She just wanted to visit a site and read things. It was very annoying.

    Drop Server Load

    Okay. So this part worked.

    Graph showing Server load on day 3 leveled out

    It only shows up starting day three because I didn’t flip DNS over right away. I had to turn off PageSpeed, upgrade PHP, make sure nginxcp was going to work with it… There was prep work. Day three, the little spikes vanished. You still get big ones because that’s when the server runs backups and upgrades. The little spikes are, normally, when I have a new post on the site.

    There’s been no perceptible change to bandwidth. All other sites on the server are, however, notably faster.

    End Result?

    It looks like CloudFlare worked. The stats say I’m using 25% less CPU with CloudFlare, which is interesting, but now that it’s baked, I want to try something else, just for grins and giggles.

  • CloudFlare’s SSL

    CloudFlare’s SSL

    CloudFlare’s been pushing SSL for a while as a new feature. We all know that SSL is a great idea, that any time you have someone logging in, it should be secure. If you’re handling money, it should be secure. If you’re taking any personal information, for god’s sack (sic), make it secure!

    A major problem with this has often been the cost overhead. You can self-sign your certificates, but that pops up with other errors for people. Really what we want is a simple, non-super-expensive, way to have security where and when we need it. Until Let’s Encrypt gets its kick off later this year (and probably for another year after that), it’s complicated and expensive to set up shared hosts with certificates, even if you use SNI.

    Enter CloudFlare and their bold proclamation that they’re going to provide free One-Click SSL for everyone, even their free-plan users. This is great! Except that it doesn’t work quite right.

    First off, if you use the flexible SSL plan, the one that doesn’t change your URL to HTTPS, then you need to use a plugin line CloudFlare Flexible SSL. Or you can just toss this into your wp-config.php:

    #SSL
    if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
    	$_SERVER['HTTPS']='on';
    } else {
    	$_SERVER['HTTPS'] = false;
    }
    

    Secondly, if you’re not actually changing the URL to SSL, you’ve got a problem. I don’t want my users to hit https all the time, not for all my sites. And all the reasons we don’t use https everywhere aside, it’s something to keep my running costs down.

    My rule is that SSL should be used anywhere where you are transmitting information that should not be public, and this suddenly was an issue when I looked at the levels of security. The one I’d want would be Full SSL, as it “Encrypts the connection between your site visitors and CloudFlare, and from CloudFlare to your server.”

    And there are two types of Full SSL, one of which is ‘Strict’ and requires you to have your own SSL cert, be it purchased or self-signed.

    CloudFlare SSL for everything? Not exactly: Full SSL (strict) is too strict.

    The obvious implications here, however, are that everyone would see HTTPS in the URL, and I don’t really want that. Of course, that’s not what they meant. What they mean is that IF you use https in the domain, then CloudFlare double encrypts. Otherwise it remains http for the domain.

    So basically normal SSL. And this is what I want, because I do have a purchased SSL cert for the domain in question and I do want to be secure all down the line. If I was using a self-signed certificate, I’d use the Full SSL (not strict) and that would work as well.

    One important thing to keep in mind is that if you chose to use the Flexible SSL, you’re not giving yourself login protection! As they point out, this gives you an encrypted connection between your site visitors and CloudFlare, but not from CloudFlare to your server. This greatly reduces the possibility of being sniped or sniffed, but the content from CF to use isn’t secured, which means if you use Flexible SSL for your store, you’re a moron.

    With that in mind, what good is it? Well you can be promised security throughput for your domain, and that, if you’re using CloudFlare, is a great thing.

  • Stop Using Copy Protection

    Stop Using Copy Protection

    I’ve seen a million features out there to ‘prevent people from stealing your content.’ The idea is that by preventing people from (easily) copying your work, you stop them from stealing it and profiting off your efforts. You may even think that you’re saving your images from being stolen. In general, they use javascript to prevent things like right-click, view source, copying text, and disabling keyboard short cuts. In general, they suck and here’s why.

    User Experience

    Anyone who uses a screenreader or an alternative mouse tool now, officially, hates you. You’ve made your site look like absolute crap. Some screen readers can no longer read your content at all. Also not everything handles javascript very well (which is by far the ‘most popular’ way to block out content) and that makes for a pretty lousy experience for your visitors.

    Support

    If you have a problem with your website and ask the world at large for help, they will take one look and hate you. No one can easily help you with your CSS or your layouts or your design now, because you’re protecting content. When customers ask for help, the first thing I do is turn those plugins off so I can use my normal debugging methods and not worry about cruft interference.

    It Doesn’t Work

    If you disable right-click, you make it harder for me to bring up Chrome’s dev tools, but not impossible. You can’t make it impossible. This is, in part, because there are so many different browsers to account for, but also because developers really don’t want you to be able to kill dev tools. We need them to fix the web, and if I were to leave the dev tools open and then visit your site I would be able to have it open on your site.

    Once I have dev tools open, I can view the resources loaded by your page. Take Instagram, who doesn’t let you right-click on an image to download. I can instead right-click, chose ‘Inspect Element’ and I get this:

    element.style {
        background-image: url(http://photos-g.ak.instagram.com/hphotos-ak-xaf1/t51.2885-11/10912600_6619567248918_1818171895_n.jpg);
    }
    

    Guess what I can do now? Load that URL in another window, download, done. If that’s not available, I’ll go over to the Resources tab, open up the Instagram folder, then Images, and find the image I want. Again, done.

    There’s Only One Way

    There is but one foolproof way to prevent your content from being stolen: Don’t publish it.

    But of course no one wants to hear that. So what’s the other way? Well give up on not having your words stolen. Even if you make it difficult, people will get at it. People type up books and scripts today, they’ll do it for your website if they’re properly motivated. Images, on the other hand, are a different issue. If you’re a photographer, don’t put your full-sized images online unless you’re selling them. And if you are selling photographs, put them on a cloud host like Amazon. Large files and PHP aren’t the best of friends anyway. Your website, unless it’s a store, doesn’t need the 10meg image file.

    As much as it pains me to say it, DRM is also a solution. So is watermarking your images. The way people like Getty protect their images is to lock it down to purchased users only. You can (fairly easily) download the smaller, sample images, but the awesome big ones are locked down.

    But that’s how you protect your content. Not with those plugins.

  • Being Smart Cures Headaches

    Being Smart Cures Headaches

    While reviewing WordPress plugins, I often kick a plugin for calling file locations poorly. This usually happens when they’ve hardcoded their plugin name or (worse) wp-content into paths.

    When you hardcode in paths, or assume that everyone has WordPress in the root of their domain, you cause anyone using ‘Giving WordPress it’s own directory’ (a VERY common setup) to break. In addition, WordPress allows users to change the name of wp-content, so you would break anyone who choses to do so. And when this happens, I always link them to how to figure out the constants, which leads them to the function plugins_url().

    In many ways, plugins_url() is a panacea, a silver bullet, because it can take this:

    <?php
    echo '<img src="' . plugins_url( 'images/wordpress.png', __FILE__ ) . '" > ';
    

    And magically turn it into this:

    <img src="http://www.example.com/wp-content/plugins/my-plugin/images/wordpress.png">
    

    Even better, if you put the plugin in the mu-plugins folder, it would know to be this:

    <img src="http://www.example.com/wp-content/mu-plugins/images/wordpress.png">
    

    That makes it insanely flexible and wonderful.

    This allows me to happily rename a plugin folder to my-plugins_off to force disable it and will reward me with this error:

    The plugin my-plugin/myplugin.php has been deactivated due to an error: Plugin file does not exist.

    I like that error. I like that it happens no matter what, once I’ve renamed that plugin folder and I refresh a page that uses the plugin, it’s gone. Of course, sometimes it’s not enough, but most of the time, if you know what plugin’s being a doofus, you can fix it with that.

  • Don’t Reinvent the Wheel

    Don’t Reinvent the Wheel

    In WordPress, I punt plugins now and then for doing weird things that can best be described as reinventing the wheel.

    Any time a plugin replicates functionality found in WordPress (i.e. the uploader, jquery), it is frowned upon. It presents a possible security risk since the features in WordPress have been tested by many more people than use most plugins. Simply put, the built in tools are less likely to have issues.

    This was always something a little theoretical. I hadn’t yet run into someone who had broken their code with an upgrade of WordPress just because we updated the core wheel. Until November 20th.

    The shortcode API in WordPress was updated. It was decided that in order to stop breaking on PHP 5.4.8 and under, we needed to apply wptexturize() to shortcodes. This had a fun side effect when people didn’t properly register shortcodes, which of course brought up the logical question … why wouldn’t you register your shortcode?

    What I generally see in plugins is someone’s using a filter to look for their shortcode instead of registering it, so the post content is, in it’s entirety, parsed. That always struck me as foolish, since posts can get pretty long if Chris Lema or I are writing. And the reason people would do it was also odd. Either they were being lazy, they didn’t know about shortcodes (which I can understand, you can’t know everything), or they were trying to get around an ‘issue’ with nested shortcodes.

    For what it’s worth, the shortcode parser correctly deals with nested shortcode macros.

    [tag-a]
       [tag-b]
          [tag-c]
       [/tag-b]
    [/tag-a]
    

    That works fine. This won’t:

    [tag-a]
       [tag-a]
       [/tag-a]
    [/tag-a]
    

    Now I want to note, I’m using a php shortcode around those tags. So yes, it works great. But the problem would be if I wanted to show you the php code in a php shortcode… Doesn’t work that way, and it’s a limitation of the context-free regexp parser used by do_shortcode(). We went for speed over levels, and it can’t match each opening tag with its correct closing tag.

    Obviously the ‘right’ answer is ‘don’t nest same-named shortcodes’ but instead, some plugin authors have chosen the strategy of not registering shortcode names. That way the parser doesn’t try to mess with it. Sounds great, right?

    Not with wptexturize() running.

    [tag-a unit="north"]
       [tag-b size="24"]
          [tag-c color="red"]
       [/tag-b]
    [/tag-a]
    

    That turns into this:

    [tag-a unit="north"]
       [tag-b size=&#8221;24&#8221;]
          [tag-c color=&#8221;red&#8221;]
       [/tag-b]
    [/tag-a]
    

    Basically the code is understood to be code and not a quote. That means it would simply output the tags as code and not the tag content.

    And you see why this is a problem.

    There are two answers to fix this. One is to turn off wptexturize for your pseudo-shortcodes (via the no_texturize_shortcodes filters which are not complete, sadly, if you need to unfilter shortcode variables) and the other is to use the Shortcode API as it was intended. I would, personally, suggest you use the API since that prevents your code from breaking like this if another security update happens.

    Which brings us back to why reinventing the wheel is generally foolhardy in robust, well maintained systems. WordPress is constantly being improved, fixed, patched, and secured. The more you work around it by making your own way, the harder it is to fix things when WordPress makes a change. You’d think that people who make their own wheel would be attentive to anything that might break it, but they rarely are. They make their way, forget about it, and get annoyed when their code breaks and blame WordPress for not warning them. That’s a dirty secret about Open Source. No one’s going to tell you that a change will break your code. They expect you to be paying attention.

    The absolutely worst part about all this is that your users will have to decide to either stop using your code (which isn’t always an option) or not to apply an upgrade. In the case of 4.0.1, this is dangerous. This is why I will keep telling you not to reinvent the wheel, unless the wheel really needs it. And if the wheel needs a reinvention, you should consider submitting a patch to WordPress core, because if it’s that bad, everyone should know.