Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • URL Validation

    URL Validation

    I was writing a script for a rather complex series of checks on a website. I wanted to do what I thought would be simple. I wanted to grab the website headers and parse them to check if a site was WordPress or not.

    That was a weird and wild trip.

    In theory, this is all the code you need:

    filter_var($url, FILTER_VALIDATE_URL)

    But as it turns out, that’s actually not the best thing! I started using it but found that I could break it pretty easily and, since I was writing a tool I knew would be used by end-users (who are exceptionally creative when it comes to breaking things), I googled around and found this blog post on Why URL validation with filter_var might not be a good idea.

    Yikes! All I was mad about was that FILTER_VALIDATE_URL thinks http://foo is okay, even when you tell it you want the damn host.

    In the end I used this Strict URL Validator code but even then I had to wrap it around this:

    	// Sanitize the URL
    	$gettheurl  = (string) rtrim( filter_var($_POST['url'], FILTER_SANITIZE_URL), '/' );
    	$gettheurl  = (string) $_POST['url'];
    
    	if (preg_match("~^https://~i", $gettheurl)) {
    		$gettheurl = "https://" . $gettheurl;
    	} elseif (!preg_match("~^(?:f|ht)tp?://~i", $gettheurl)) {
    	    $gettheurl = "http://" . $gettheurl;
    	}
    
    	// Is it a real URL? Call StrictURLValidator
    	require_once 'StrictUrlValidator.php';
    
    	if ( StrictUrlValidator::validate( $gettheurl, true, true ) === false ) { 
    
    		// Do the needful
    	}
    

    In many ways, this makes some sense. What is and isn’t a URL can be tetchy to check. http://foo is real. I can use it locally. That’s why http://localhost can exist. And we can’t just say “if not .com/org/net” anymore (if we ever really could). But boy is my code clunky.

  • Mailbag: Getting Started as a Freelancer

    Mailbag: Getting Started as a Freelancer

    Neil asks:

    I am a web technician and proficient in Wordpress. I’ve worked on a number of WP sites, as well as other types of scripts/sites. Some of my work has been volunteer, and assisted by Dreamhost’s non-profit hosting. Would you have any suggestions as to how or where one might be able to start in obtaining freelance work? I know it’s a bit presumptuous but I thought I’d ask- I’ve seen many of your posts in the Dreamhost forums helping out. Kindest Regards, Neil

    I should preface this with a reminder that I’m not a freelancer for a reason. I hate the constant hustle of it.

    I don’t think I’m really qualified to answer this one. But you know who is? Chris Lema. And you know who talked on the Matt Report about how to become a great freelancer?

    But that doesn’t answer where one gets freelance work.

    If I had to start from zero, I’d pick the WordPress Jobs Board and snag a couple people there. Chris Lema supports Codeable, though, so that’s also a really good pick.

    Hey readers, who do you use?

  • Design for Multisite or DIE

    Design for Multisite or DIE

    I don’t mean you need to design all your code to have special Multisite features. I mean that if you’re not writing code to work on multisite, you’re probably doing a lot of things non-optimally and not fully WordPressy. When you write your code with Multisite in mind, you’re actually writing it with the basic tenants of WordPress itself. It forces you to think about how WordPress is used, how it might be used, and how you can be flexible and extendable.

    Let’s throw out the idea of network options and activation for a moment and consider the ways we can write our code to make it work for Multisite and the world. The truth is that if you’re coding ‘for Multisite’ in many ways your coding for WordPress in the best way possible.

    Calling Files

    There’s a time and a place for ABSPATH but it’s as a last resort. There’s a time and a place for get_bloginfo('url') but it’s not to call .'/wp-admin/admin.php either. Did you know admin_url() will get the url to the admin area using the right protocol (http or https) for you? And it works for Multisite. Instead of hardcoding your paths or assuming everyone has WordPress installed in the root of their website (they don’t), use the functions and template calls WordPress has created.

    Oh and stop supporting the old WordPress 2.x ways of determining folders. It’s 2015. We’re good.

    Saving Files

    Saving data to the disk means everyone can read it. Duh, right? Well, where do you save uploaded files? You use wp_upload_dir of course. That works on Multisite just fine. Instead, if you hardcode in /wp-content/uploads/myplugin/ then you’re saving things for everyone. If you’re not using the WordPress options to grab the upload directory, then your code won’t work on Multisite and everyone will be sad.

    This extends to where you save your cache files. Did you know there’s a plugin that saves the cache to the plugin folder itself? Besides the fact that the cache didn’t have a way to flush and grew to 700megs over the year the person used it, that cache was for all the sites in the network. All. Saving the cache to a unique location (I suggest /wp-content/pluginname-cache/siteID) prevents cross contamination of cache.

    Saving Options

    If you write a plugin that, to save its data, it creates a new DB table and saves it there, that can be okay. But if your plugin on update then drops that table and recreates it… That was not pulled at random, by the way, I was reviewing a plugin that did that. Instead he should have been using the function update_option() to create (and update) the options. And yes, it knows.

    But that’s an extreme, I admit. What isn’t an extreme is people creating their own tables. It happens a lot. And when they do, they often forget that we have $wpdb->prefix which means they force create wp_mypluginname instead of $wpdb->prefix . "mypluginname" … guess which one’s smart enough to know it’s on Multisite?

    (If you want to make a network table use $wpdb->base_prefix and use update site option for network wide options, yes, we know the naming conventions are weird.)

    Theme Customizer

    Not everyone can edit theme files. Not everyone can make child themes. On a Multisite, the only person who can do that is the Super Admin. Site Admins have no access to edit files or upload themes. Worse, if you make a change to a theme, everyone who uses that theme gets the change. What happens when a site wants a special header and your theme doesn’t allow those to be edited via the customizer? The customizer is there for a reason. Use it. At the very least make things hookable to allow plugins to do simple things like change footers. Please. Please. That’s one of the things that themes get wrong constantly.

    What Else?

    What do you think would be improved if people ‘coded for Multisite’?

  • Self Ghosted

    Self Ghosted

    I had to restart everything.

    You see, getting Node.js and apache to work together wasn’t going to fly, so I went and built a new VPS with Ubuntu over on DreamHost. Obviously not everyone has this luxury, but since I do, and since DreamHost made this as easy as clicking on a box, I thought it would be perfect.

    Requirements

    You have to be shell savvy for this. Sorry. There’s no other way. Just accept that and move on.

    You need a VPS. The new Ubuntu SSD VPSes all have a one-click ability for Node.js which makes life easier.

    You should use nginx and not apache.

    Ghost requires Node.js 0.10.x (not 0.12.x). They recommend Node.js 0.10.36 & npm 2.5.0. Of course, DreamHost installs node 0.12.x and npm 2.5.x. You can check by typing node -v and npm -v to see what versions you have. Does this mean you can’t run Ghost? No, it’ll work, but it’s not what they like.

    You’ll also need an ‘admin’ account on your server. From panel, click on “VPS” and then “Manage Admin Users” to add a new user to that box.

    Get Node.js on your VPS

    This is quite simple. First, get an Ubuntu VPS. All the new boxes on DreamHost are Ubuntu, so this is the easy part. Once you have the VPS on DreamHost, make a new domain. I made ghost.elftest.net and in the settings, I checked a box to use node.js:

    Enabling Node on DreamHost is Easy - click a box

    That will force my file path to be ~/ghost.elftest.net/public (normally on DreamHost it’s ~/domain.com you see) but that’s not an issue since this is a new box. That path will be my ‘home’ folder for the domain and where I install everything (if someone asks you ‘where is X installed on your server?’ you tell them that path). That path also means that had I already been using that domain, it would mess up my folders and paths. If you’re doing this on an existing domain, keep that in mind.

    Install Ghost

    Like I said before, you have to install on your server, not your desktop. Every single doc I read told me I HAD to do this as the server admin, someone with sudo access. I really, really, really did not like that. I mean, epic levels of hate for the idea that I couldn’t have my user account own things, and have the code in my darn web folder.

    Me being me, I hatched a plan. I was just going to do it. I was just going to install it in my webfolder and see how it goes. I came up with this theory because when I read How To Install Ghost on DreamHost I noticed it wanted me to have a specific user chown the folders. Not the admin user, but a special ghost user. So what if I just made ‘elftestghost’ the ghost user, and what if I just used ~/ghost.elftest.net/public/ghost/ as my install directory instead of /var/www/ghost/? And this way, I’d be able to pop in and edit things as my normal user.

    So here’s what I did.

    $ curl  -L https://ghost.org/zip/ghost-latest.zip -o ghost.zip
    $ unzip -uo ghost.zip -d ghost
    $ cd ghost/
    $ npm install --production
    

    That’s it. Ghost is installed. I expected that last step to fail and I’m still a little surprised it didn’t. If it does fail for you, run it as your admin account with sudo, and then chown it over to your ‘owner.’

    Configure Ghost

    Now that Ghost is installed, you may wonder where it is. We haven’t finished the install yet as it happens. We need to configure it and to do that, we copy the file config.example.js to config.js and open it up.

    Once you look at it you see that there are multiple ‘config’ options. Since we called --production in our start command, logically we’re going to edit that section. And lo, there’s the bad URL:

    config = {
        // ### Production
        // When running Ghost in the wild, use the production environment
        // Configure your URL and mail settings here
        production: {
            url: 'http://my-ghost-blog.com',
            mail: {},
    

    Change that to the right URL. Mine is http://ghost.elftest.net

    Also look for this:

            server: {
                // Host to be passed to node's `net.Server#listen()`
                host: '127.0.0.1',
                // Port to be passed to node's `net.Server#listen()`, for iisnode set this to `process.env.PORT`
                port: '2368'
            }
    

    Change the host to 0.0.0.0 and save the file. You can also set it to the IP of your server, but as that might change, it’s not required.

    Finally you’ll want to set up mail which can be complex. I set up a special account on my own server.

    Setup Ghost

    Seriously this is not a five minute install. Your site starts with a Hello World type post which tells you all about the glory of Markdown. If you go to your admin page (http://ghost.elftest.net/ghost/) it sends you to http://ghost.elftest.net/ghost/setup/ where you get this:

    Ghost: Create User

    This actually makes more sense than it did on the Ghost Pro site, where I was wondering why I had to make a user and then a user. Here I’m clearly making a user for the site. There I was making a user for their network (Ghost Pro) and then one for my site.

    Setup Nginx Proxy

    Will it never end? The reason we want to do this, and this is why we’re on nginx and not apache, is in order to have a pretty URL without the port number.

    Log in to your server as your ‘normal’ account (the one who owns the domain, not the admin) and make an nginx folder for config:

    cd ~
    mkdir -p nginx/ghost.elftest.net
    

    Then make a file called ghost.conf with the following:

    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://localhost:2368;
    }
    

    Restart nginx (which yes, you need the sudo power for so yes, you need an admin account) and it’ll magically work. If you get a “502 Bad Gateway” error, it’s because Ghost isn’t running. Speaking of…

    Make Ghost Always Start

    Okay so I actually do need my admin account. I went with the init script approach to keeping the Ghost always on.

    $ sudo curl https://raw.githubusercontent.com/TryGhost/Ghost-Config/master/init.d/ghost \
      -o /etc/init.d/ghost-elftest
    

    Then I edited the ghost-elftest file:

    GHOST_ROOT=/var/www/ghost
    GHOST_GROUP=ghost
    GHOST_USER=ghost
    

    I changed that to where ghost was really installed, but it brings up an interesting thought. What if I wanted multiple ghost instances? Well that’s actually why I named the file ‘ghost-elftest’ instead of ‘ghost’ (which they recommend). With this setup, I can name an init file for each instance and run the commands as sudo ghost-elftest start and so on. Keep in mind, you also have to pick a custom port for each instance.

    There are three final commands to run in order to force Ghost to start up on reboot:

    $ sudo chmod 755 /etc/init.d/ghost-elftest
    $ sudo update-rc.d ghost-elftest defaults
    $ sudo update-rc.d ghost-elftest enable
    

    Now I can use Ghost to my heart’s content.

    Conclusion?

    A WordPress killer this is not. It’s just not. If they can make it run without the need for admin/root/sudo access, it has a chance. Once it’s set up, it’s quite nice, but the 5 minute install this is not, and it’s going to need that to beat the beast.

  • Mailbag: Ghost Image Errors

    Mailbag: Ghost Image Errors

    Once I got Ghost up and running, I got some errors and there was venting around the usual places. Image uploads were failing. I cried. Then I solved it. Then someone asked a logical question.

    How did you fix the image upload issue?

    What happened was that I found I was getting a Wiggly Cat whenever I uploaded an image. Eventually the upload failed.

    Ghost's wiggling cat

    The cat bounced up and down. My wife eyed it and said “That’s not much of a chuffing SOS now, is it?” (no, she’s not British, but what else can you say about that?). Thankfully, after years of WordPress support I went right into the file system and checked if the images were being uploaded at all. Answer? Sort of.

    $ ls -lah
    total 0
    drwxr-xr-x 2 elfghost elfgroup 131 Apr 15 17:22 .
    drwxr-xr-x 3 elfghost elfgroup  23 Apr 15 17:12 ..
    -rw-r--r-- 1 elfghost elfgroup   0 Apr 15 17:13 f4c134eb021e026414a1bd23d3c5c927-1.jpeg
    -rw-r--r-- 1 elfghost elfgroup   0 Apr 15 17:12 f4c134eb021e026414a1bd23d3c5c927.jpeg
    -rw-r--r-- 1 elfghost elfgroup   0 Apr 15 17:22 unicorn.jpeg
    

    0 bytes isn’t right. But again, WordPress support history to the rescue. I checked my /tmp folder, saw it was full, turfed the entire thing, and the upload worked. Rather fast, too, since it’s not making an image resizes. I will note, had that fix failed, I’d have started playing with folder permissions, but since I got the 0-byte version, I was reasonably sure that wasn’t my issue.

    Two humor tidbits for you.

    Bing thinks I write in Turkish:

    Ghost! What is this cat and the error and the aaaaaaiiahsfdhkjdfgjklhdgkjhfgd? (Bing thinks it's turkish)

    Here’s a cute bouncing cat:

    Pusheen The Cat
    Pusheen The Cat
  • NUX: Setting Up Ghost (Self Hosted)

    NUX: Setting Up Ghost (Self Hosted)

    Once I used Ghost Pro, I thought about self hosting. I have a WP site that’s basically wasted as a WP site. It’s small, it’s static, and it rarely changes. I thought it would be perfect for Node. There are also a couple of small, basically HTML, sites I run in the back of things. This would be fine to manage that.

    But first I had to address a major misconception.

    You Install Ghost on Your Server

    For some reason in my head I had this working like Jekyll, which I would install on my computer and push up to my server. No, I’m not so much installing Ghost as Deploying Ghost.

    But I Installed Ghost On Your Computer

    I decided to do this anyway, just to see what I was getting into.

    To install Ghost you must install Node.js first. Since I have Homebrew, this is two commands:

    $ brew unlink node
    $ brew install node
    

    I had an older version of Node.js installed for whatever reason.

    Sadly I can’t install Ghost this way.

    My Brew output for installing node.js and not Ghost

    Next you download Ghost (I was download 564,730) and at this point I hesitated. The directions don’t tell you where to put the files. It just says this:

    Next, grab the newly extracted ‘ghost-#.#.#’ folder and drag it onto the tab bar of your open terminal window, this will make a new terminal tab which is open at the correct location.

    Since I know that upgrading involves replacing the files, I’m no fool, and I made a new folder setup: ~/Sites/ghost/sitename.com/ That’s where I ran node commands:

    $ npm install --production
    $ npm start
    

    Done. Now I have Ghost up and running locally.

    Install Ghost on My Server

    In a word? Ow.

    The main issue is Node.js and Apache both want to use the same ports. That’s impossible. And I want to keep Apache running port 80 because this VPS runs… well… WordPress. This is where I stopped the first time I tried to do all this and tossed this post into a long draft.

    There are directions on How to Host Ghost on an Apache Subdomain, which luckily is what I wanted to do. Except it was complicated and messy and required root.

    So the NUX here? Absolute crap. It’s just not something a new user would want to do, be able to do, or be able to maintain.

    And that sucks.

    Ghost’s got a great interface, one that I like better than WordPress for blogs and simple sites. It’s nailed simple in a way we crave. But it came at a cost. WordPress’s simple to install is fraught by it’s IDIC complex. Infinite diversity in infinite combinations, with the themes and plugins, lends WordPress amazing abilities but a pretty insane learning curve. Ghost I could sort out in a couple hours but you really can’t do too much with. I wouldn’t use it for a store. I might use it for a blog if I had to start over.

    Except I can’t (easily) self host it because of stupid Node.js.

    If they can sort that out, make it so I can easily, without root, install and manage Ghost, I’ll be back.

    Until then, Managed Ghost Hosting is the way to go. Or WordPress. Take your pick.