WordPress Filesystem Abstraction FAQ

I shouldn’t have to be writing this, But as some people will know, I’m utterly sick of repeat questions.

This is a FAQ on the WordPress FileSystem abstraction which i wrote as part of the Summer of Code project to implement a Plugin Upgrader for WordPress (note: the actual upgrader in core is different from what i originally wrote, however ideas and code were lifted and put in their place by a much better coder than I), The content of this post is based on the situation as of today, 20/Feb/09, I fully expect these answers will not remain current in the years to come, But hope they provide some background information on them.

The FAQ:

What methods/transports does WordPress support for accessing the filesystem?

  1. Direct – This method uses direct file IO operations from PHP
  2. FTP – This method connects to your FTP server using the credentials supplied, and performs all IO operations that way
  3. SSH – This method uses the PHP SSH2 extension to connect to the server and manipulate the files there.

What requirements must be met for a transport to be used?

  1. Direct
    • The files which PHP creates MUST be owned by the same user as the WordPress files which have been uploaded
  2. FTP
    • The user will need to supply their FTP credentials in order for it to operate
    • The FTP code branch requires either:
      1. The PHP FTP Extension to be loaded, OR
      2. The FTP Sockets Extension to be loaded, OR
      3. The PHP Function FSockopen() to be available
    • In the case of  the Sockets or Fsockopen case, The 3rd party FTP Class “PemFTP” is used.
    • I should also mention, That this supports Secure FTP as well.
  3. SSH2
    • This was added in WordPress 2.7
    • It requires the PHP SSH2 Extension to be available, This generally requires compiling from source unless you’re lucky enough for it to be available in Pecl for your distribution.
    • Unless you’re running a Dedicated or VPS server, This is not usually available to you due to the above.

Why does my WordPress Install require my FTP Credentials? My other blog doesn’t!!

As above, The Direct Method(Which requires no credentials) only works in a very certain setup, Generally, This is only servers running with suPHP or suExec with PHP as a CGI – Servers running this exist, however, Due to hardware constraints (running these uses extra resources) most hosts which oversell do not use this method.

What can i do?

Move to a different Hoster, Or if thats not an option, Simply entering your FTP details.  You can see a item later in this FAQ for how to hard-code these settings if you want.

No, Seriously, Why cant i use the Direct method? I think i should be able to!!

Because your server configuration is not supported.

Still not taking no for an answer? Ok, Heres the problems with each of the requests people ask for:

  1. I dont want to give my FTP details, I’d rather just chmod 777 everything
    • The problem with this, Is its insecure, WordPress shouldn’t be encouraging non-secure installation methods, Yes, I realise you need to chmod your uploads directory in a few cases, And thats OK, Its a convenience,  Its annoying to have to enter credentials every time you want to upload a file..
    • Yes, WordPress could write to your files in that case, But if you read on to the next point:
  2. I should be able to use it! I’m in the group which PHP runs as! (usually the same as your web server)
    • Thats all nice and well, And that means that PHP can write to your WordPress folder, However, Its got one big gotcha, Whilst it can write to the directory, Theres an issue: The files PHP create will be owned by the webservers username, And the group will be set to that group, the files will NOT be owned by your username.
    • So what i hear you say, I dont care if its not owned by my username, Ok, 2 issues at play here now:
      • You will encounter errors upon attempting to delete the files via FTP, Simply due to the fact you do not own the files.
      • Much on the same path, Because you do not own the files, If you have a Disk quota on the webserver, some encarnations will miss your files and not count it (Hooray! I hear you yell, Thats all good and fine, But if you dont like paying for disk space, find somewhere else that will sell you the even more oversold disk space!)

My FTP Doesnt work!

Ok, This isnt too common, But sometimes PHP’ will have dodgy extensions, or configurations, infact, Its VERY common for a hoster to have a crap install of PHP, the FTP extension and CURL are common culprits for being badly configured, Unfortunately, Theres not much you can do to fix stupid hosts, other than complain.

As a work around, You can use a plugin, or a filter yourself, to work around such circumstances, While I never intended this plugin for end-users, If enough people require it, I’ll separate the needed functionality into a separate Plugin:

Introducing Core Control, Core control is a plugin which gives some extra control over certain items in WordPress, Mainly Filesystem access and HTTP access. Utilising this plugin, You can disable certain Filesystem access methods, Simply install it (The Plugin installer works great for this, Try it again if you’ve disliked the search in the past, The new Search system that went live on WordPress.org recently has improved things greatly there) and enable the Filesystem Module, Once thats done, You can simply disable the current primary transport (Hopefully its the Direct or FTP Extension method) and see if the next in line works for you:

Core Control: Disabled FTP Extension
Core Control: Disabled FTP Extension

I run FTP/SSH on a non-default port!, How can i use this with WordPress?

You can include the port in the hostname, For example, Instead of writing “dd32.id.au” i could use “dd32.id.au:4567” if i was to run on port 4567

FTP Host on alternate Port
FTP Host on alternate Port

WordPress complains that it cant find my WordPress installation!

Whilst this should be highly uncommon (I Hope!), It can happen sometimes, So read on to the next item for a solution.

I have to use the FTP/SSH method, But i dont want to enter my password every time

WordPress also supports the use of defining a selection of constants to ease the sitatuation for a few select circumstances, The supported constants (and a description of each) are:

Constant: Description: For Example:
FTP_HOST The hostname of the server to connect to define(‘FTP_HOST’, ‘dd32.id.au’); or

define(‘FTP_HOST’, ‘dd32.id.au:4567′);

FTP_USER The username to connect with define(‘FTP_USER’, ‘dd32′);
FTP_PASS The password to connect with, WordPress will remember all your other settings by default, However, It will forget your password every time you provide it (ie. it is not stored on the server), You may use this to hard-code your FTP password define(‘FTP_PASS’, ‘*************’);
FTP_PUBKEY (SSH2 only) The path to the Public Key to use for the connection define(‘FTP_PUBKEY’, ‘/var/key.pub’);
FTP_PRIKEY (SSH2 only) The path to the Private Key to use for the connection define(‘FTP_PRIKEY’, ‘/var/key’);
FTP_BASE The path on the FTP server to the WordPress files, This is absolute path in the FTP session, NOT an absolute path on the server. This should be set to the ABSPATH folder define(‘FTP_BASE’, ‘/public_html/wordpress/’);
FTP_CONTENT_DIR The path to the Content directory on the server, This is mainly useful for times when WP_CONTENT_DIR has been set, However, it should work without it in most cases. The warnings in the previous item hold true. define(‘FTP_CONTENT_DIR’, ‘/public_html/wordpress/wp-content/’);
FTP_PLUGIN_DIR The path to the Plugins directory on the server, This is mainly useful for times when WP_PLUGINS_DIR has been set, However, It should workout this in most cases. The warning for the previous items hold true. define(‘FTP_CONTENT_DIR’, ‘/public_html/wordpress/wp-content/plugins/’);

By default (And you cant change this without a plugin) WordPress saves all your entered details in the database (except password, It only stores the server address, port number, and username), If you do this once, WordPress will remember them, You may then define your password in your wp-config.php file if you so wish. But be warned, In the case where your server is compromised, OR if other users on the system can read your files (As some badly setup shared hosts are), then you may be leaving yourself wide open to an attack if anyone ever feels like it.

Why doesnt WordPress support Method XYZ for acess?

Because no-one has contributed a patch to add support for it. In WordPress 2.5, SSH was not supported, this was only added in a later version (2.7) due to someone doing enough work on it for it to be included.

Why do you see yourself as the end-all for this?

Some people might be surprised to hear(And others will not be surprised) that i get this a lot, But i do. In short, I dont, Please, Go ahead and implement your ideas, I mearly voice my opinion, My opinion does not prevent something from being included, But due to my involvement, A yes from me, Might give a bit more weight to getting something in, The same goes for all the core developers, And all those of us (me included) who regularly contribute patches to WordPress.

WordPress is a comunity effort, Due to the size of the community though, There will always be some who are more well known than others, and thats unfortunate, But its impossible for core developers to keep track of everyone. Some people have said in the past that WordPress was being developed by a core few people who did what they wanted, and didnt take others thoughts into consideration. In some ways this is true, Matt for example, Has in the past said he didnt want something to happen, Due to the respect and the weight he carries, his voice might be the deciding vote, But plenty of times will there be things commited which Matt does not agree with. Many of the core developers develop code and features which users request, even if they have no need for it themselves, I would not be surprised if the top 20% of developers of WordPress only used 10% of its features. I personally for example, Have made very little use of the Plugin upgrader and installers.

So to wrap this item up, No. Just no. I will voice my opinion, However, Take it with a grain of salt, Just like everyone elses, If you want to rip every single contribution i’ve made to WordPress out, and replace it with something you see as better, DO IT, if its better, then great, WordPress will be better off. I will do the same thing, If i see someone submit a patch which i feel could be done in a better way, Then i’ll submit a alternate patch, Quite often it’ll be a “wow, i didnt realise it could be so simple” or a “that looks much cleaner!”, or even “Isnt that what my patch does????” Deal with it, And move on.

You forgot to answer something!

You know, I probably did, So if its before the end of March 09, Add a comment, and i’ll add it to the list. Why March? Quite simple really, After a month, i’m unlikely to care enough to update it. I might write an updated post in the future which corrects things here, or updates it for whatever is in wordpress at that point in time.

I hope this has been of some use to someone out there. If it has been, Then its served its purpose.

Hemlock on Vimeo

Here’s a film I made for the latest CGSociety challenge…the theme was to adapt an ancient myth to steampunk stylings. I chose the myth about the fountain of youth for my topic.

Here’s some exceedingly lovely student CGI animation that also manages to tell a great little story. I’m reminded of Neil Gaiman’s story “Other People” from his excellent collection Fragile Things (to say more would be a spoiler!).

I’ve also included the Making-of video.. Pretty impressive short animation though.

via Hemlock on Vimeo & BoingBoing

How powerful nature can be: Bushfires in Victoria, Australia

Whilst I could’ve chosen any of the images, these’ll do.. (And “Something Cool” Might not be the best labeling for this, Considering its pretty hot..)

Craig Kidd looks at the melted metal of alloy wheels from his burnt out vehicles after a bushfire swept through his property on February 9, 2009 in Bendigo, 160 km from Melbourne, Australia. (Scott Barbour/Getty Images)

Senior Wildlife Officer Geoff McClure inspects the fire front at Mt. Cathederal, near Alexandra, some 120 kilometres northeast of Melbourne on February 9, 2009. (WILLIAM WEST/AFP/Getty Images)

 Senior Wildlife Officer Geoff McClure inspects the fire front at Mt. Cathederal, near Alexandra, some 120 kilometres northeast of Melbourne on February 9, 2009. (WILLIAM WEST/AFP/Getty Images)

Bushfires in Victoria, Australia – The Big Picture – Boston.com

Disable Automatic upgrades for a customised plugin

Update, for WordPress 2.8+: Please be advised that any mention of option_update_plugins(and friends) hooks will not be fired. This is due to the new Transients in WordPress 2.8. You’ll need to use the transient_update_plugins(and friends) hook instead. preferably both for 2.7 compat. – See http://groups.google.com/group/wp-hackers/browse_thread/thread/a12f70d6b649c917 for some background.

Recently there was a question posted to the WP-Hackers list asking how to disable Automatic upgrade for a plugin, Since it had been highly modified.

I was going to post in some code for it, But well.. I’ve been busy. So instead, I’ve just decided to sit back and write it up here instead now that I’ve got a day off.

For my examples, I’m going to use eShop (Simply because it was the only plugin which needed an upgrade at the time of writing this!).

So, You’ve modified the Core files of eShop because it doesnt achieve what you want, Or doesn’t have filters on something, A few days later, Up pops a update notice:

image1

Now, You don’t particularly want to Accidentally upgrade to the latest version and loose your changes, Or worse, a client upgrade and then complain it no longer works!

Now, Depending on the usage, Theres a few options and ways to go from here,

  1. Disable the upgrade notice entirely
  2. Remove the ability to do core upgrades
  3. Display a different notice instead
  4. Display a the update notice, And a reasoning for the removal

Disable the upgrade Notice entirely

This is quite straight forward really, And doesnt take much effort, Simply insert this tidbit of code into the plugins main file:

[sourcecode lang="php"]
add_filter(‘option_update_plugins’, ‘plugin_prevent_upgrade’);
function plugin_prevent_upgrade($opt) {
$plugin = plugin_basename(__FILE__);
if ( $opt && isset($opt->response[$plugin]) ) {
//Theres an update, So lets remove it.
unset($opt->response[$plugin]);
}
return $opt;
}
[/sourcecode]

Simple enough?

Of course, This method has some drawbacks, The client (Or yourself) is not notified that theres an upgrade available for the plugin, Which could open yourself up to potential exploitation later down the line if a Plugin is found to have a vulnerability in it.

Remove the Ability for the plugin to use Automatically install updates

Much like the previous, Its rather simply to achieve this too:

[sourcecode lang="php"]
add_filter(‘option_update_plugins’, ‘plugin_prevent_upgrade’);
function plugin_prevent_upgrade($opt) {
$plugin = plugin_basename(__FILE__);
if ( $opt && isset($opt->response[$plugin]) ) {
//Theres an update, So lets remove the package to prevent automatic upgrades:
$opt->response[$plugin]->package = ”;
}
return $opt;
}
[/sourcecode]

image3

Bingo, The upgrade functionality is disabled, Yet, Still notified of an update!

Of course, This might lead someone to question “Why cant i update it?”, Which is where the next 2 options come in handy

Display a custom notice

This mainly uses the code from section 1, But adds a bit of an extra step, Rather straight forward:

[sourcecode lang="php"]
add_filter(‘option_update_plugins’, ‘plugin_prevent_upgrade’);
function plugin_prevent_upgrade($opt) {
$plugin = plugin_basename(__FILE__);
if ( $opt && isset($opt->response[$plugin]) ) {
//Theres an update. Remove warning
unset($opt->response[$plugin]);

//Now we’ve prevented the upgrade taking place, It might be worth to give users a note that theres an update available:
add_action("after_plugin_row_$plugin", ‘plugin_update_disabled_notice’);
}
return $opt;
}
function plugin_update_disabled_notice() {
echo ‘<tr><td class="plugin-update" colspan="5">There is an update available for this plugin, However the plugin has been modified by XYZ Corp.<br />If you require functionality introduced with the new version, Please contact us for a quote to customize the new version of the plugin for your uses.</td></tr>';
}
[/sourcecode]

image4

Straight forward, Works well, Looks Ok-ish.. But isnt very helpful.

Disable automatic upgrade, And display a custom message

This is my favourite method, Which is why its been left ’till last:

[sourcecode lang="php"]
add_filter(‘option_update_plugins’, ‘plugin_prevent_upgrade’);
function plugin_prevent_upgrade($opt) {
$plugin = plugin_basename(__FILE__);
if ( $opt && isset($opt->response[$plugin]) ) {
//Theres an update. Remove automatic upgrade:
$opt->response[$plugin]->package = ”;
//Now we’ve prevented the upgrade taking place, It might be worth to give users a note that theres an update available:
add_action("after_plugin_row_$plugin", ‘plugin_update_disabled_notice’);
}
return $opt;
}
function plugin_update_disabled_notice() {
echo ‘<tr><td class="plugin-update" colspan="5">There is an update available for this plugin, However the plugin has been modified by XYZ Corp.<br />If you require functionality introduced with the new version, Please contact us for a quote to customize the new version of the plugin for your uses.</td></tr>';
}
[/sourcecode]

image5

Looks Alright, And for a non-power user, The extra warning is not going to bother them (hopefully), You can add some custom code to allow users to hide the update if you wish, But i’ll leave that up to you. The only downside to this is that it takes up so much room, You can style it however you want of course.

Also, You might want to prefix those functions with something other than “plugin” :) don’t particularly want to end up with conflicts!

Please Note: The technique above will only work for an active plugin. If your customer is going to deactivate the plugin for some reason, You might like to hard-code the plugin_basename() and put the PHP in your theme instead, Remember, A Theme can do everything that a Plugin can (And more!)

Sorry for the lack of indenting in those code pieces, I cant work out how to get the plugin to preserve formatting :)