Trello backup tool

Since the last decennium, I've been a happy Trello user. After one customer added me to their board, I liked it so much, that I started to use Trello for everyday planning with a few personal boards (family planning etc). Later I added a few boards for my small business and volunteer work.

There's just one thing I'm missing: Backups. I haven't been able to find a backup solution that protects my cards, my boards or my workspaces in case something disastrous happens. However, Trello does have an API, and I've been planning to create my own backup tool for multiple years now. But as the saying goes: The painter's house is never painted.

Yesterday, someone I shared a workspace with, deleted that workspace without any warning. It was gone. Boards gone. Cards gone. Irrecoverable. That will never happen to me again. So I quickly created a backup tool, with some help.

Below, you'll find a link to TrelloDownloader.zip. It contains:

  • config.php - Template for your config
  • export.php - The actual exporter. It downloads workspaces, boards, cards and comments. I found that it was impossible to download attachments due to authorisation. Since I don't care about attachments for my purposes, and I couldn't find a solution several hours in, I decided to leave that for now.
  • download_later.php - Using this file you may be able to download attachments that export.php could not get. If you know how to fix it, that is.
  • index.php - When you run php -S localhost:8123 to start php's built-in webserver, you'll be able to browse your download data via http://localhost:8123
  • exports - An empty directory for the exports to be saved in.

To use:

  1. Review the code to check that it is not malware.
  2. Put your API keys in config.php
  3. Then run export.php from the command line. You may use export.sh to run export.php. If you use export.sh from a crob job, it will save the log file.
  4. When done, run php -S localhost:8123 and to go http://localhost:8123 to see if your data is really there.

Apart from the attachment download, I spent very little time on this script. I did some basic security checks, but there may still be bugs. I didn't mean it to run on a public server, but just on your local machine.

Enjoy!

Download TrelloDownloader.zip

© GeekLabInfo Trello backup tool is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to https://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

Arrrrgh! Kill it! Kill wp_attempt_focus with fire!

Somewhere around version 2.8.4 or something, WordPress introduced a "feature" to focus the username form and wipe the username. I dont want to type my username every time again and again and again. So what can we do to kill wp_attempt_focus? There is no hook available to disable that part of the code, but we can use some dirty tricks:

I created the following 'plugin' to get rid of it:
function kill_wp_attempt_focus($in){
return preg_replace('/function wp_attempt_focus/','function wp_attempt_focus(){} function wp_attempt_focus_killed',$in);
}
if($_SERVER["PHP_SELF"]=='/wp-login.php'){
ob_start('kill_wp_attempt_focus');
}

It grabs the output of /wp-login.php, renames the original wp_attempt_focus() to wp_attempt_focus_killed() and creates a new empty function to prevent errors.© GeekLabInfo
Arrrrgh! Kill it! Kill wp_attempt_focus with fire! is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to https://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

Speed up your website: Preloading and caching images

For a customer, I'm building a website that has a pretty large header jpeg that is different for every single page. To speed up loading several pages, I've taken several steps:

1. Force browser caching

You can tell a browser to keep certain files in cache longer than normal. In apache, update the virtual host configuration or put this in a .htaccess file:
<FilesMatch "\.(jpg|jpeg|png|gif|swf|css|ico|js)$">
ExpiresActive On
ExpiresDefault A864000
</FilesMatch>

2. Install libraries

2a jQuery
On this site, I'm using jQuery to perform some tasks. As it was loaded anyway, I can use it for this task as well. So, download jQuery here and install it like:
<script type='text/javascript' src='/lib/jquery.js'></script>

2b jQuery cookie
Download the jQuery cookie plugin (by Klaus Hartl) as well
<script type='text/javascript' src='/lib/jquery.cookie.js'></script>

2c jQuery cookie
The last lib is a image preloading plugin for jQuery, that I found on engineeredweb.com:
(function($) {
var cache = [];
// Arguments are image paths relative to the current page.
$.preLoadImages = function() {
var args_len = arguments.length;
for (var i = args_len; i--;) {
var cacheImage = document.createElement('img');
cacheImage.src = arguments[i];
cache.push(cacheImage);
}
}
})(jQuery)

You can put it in a separate file, for example jquery.preload.js. And again, load it: <script type='text/javascript' src='/lib/jquery.preload.js'></script>

3. Put it all together

jQuery(document).ready(function(){
if(jQuery.cookie("preload")==null){
try{
jQuery.preLoadImages("header1.jpg","header2.jpg");
}catch(e){}
jQuery.cookie("preload",1,{path:"/"})
}
});'

This means:
jQuery(document).ready( = wait until document is completely loaded before starting new downloads.
if(jQuery.cookie("preload")==null){ = only try to fill the cache when cookie 'preload' is not found, ie. once per session
jQuery.cookie("preload",1,{path:"/"}) = set the cookie so this routine will not be executed again during this session.© GeekLabInfo
Speed up your website: Preloading and caching images is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to https://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

WordPress timezone problems: fixed

I'm using WordPress as a framework for a website that reaches over 30.000 readers daily over several media. Some over the web, but most users receive posts by mail, sms or twitter using custom-made plugins. Since I can't have a broken mail sent to thousands of users, I rather don't upgrade WordPress, except when security issues have been found. Every single WordPress upgrade I've done has broken something, like when plugin hooks are renamed, and renamed back later....

Timezone support broken

After my latest upgrade, the sending queue got seriously screwed up. SMS messages that should have been sent around 8am, got send around midnight. Why? Because WordPress timezone support screws up the time!

WordPress gave me my WTF moment while testing with date(). I've been testing what was wrong, and came across a situation where a simple reload caused the timezone to shift 2 hours. This simple line of code echoed 1:30:00 at 1:30:00 while echoing 3:30:01 at 1:30:01:
<?php echo date("H:i:s"); ?>

This isn't such a problem for simple posts on a weblog, but for sending queued mail and sms messages this is fatal.

My solution

Screw WordPress. It'll get fixed in some future version of WordPress. For now I'll get a date I can actually trust from mysql:
$wpdb->getvar('select DATE_FORMAT(current_timestamp,"%H:%i:%s");');

I also replaced several other instances of date(), like:
"select * from wp_receipients where time_to_sent<".date("Hi")."'";
to
'select * from wp_receipients where time_to_sent<DATE_FORMAT(current_timestamp,"%H%i")';© GeekLabInfo
WordPress timezone problems: fixed is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to https://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

WordPress: Pass variables by reference with apply_filter

WordPress has this great filtering system which allows you to write plugins. Yesterday, I was writing a plugin that has the ability for other plugins to change it's behaviour.

For the particular functionality, it would be very nice to use two parameters, which should both be changable.

Standard PHP

In standard PHP, you could do:

function doit($in, &$var2){
    $var2=true;
    return $in+1;
}
 
$changed=false;
echo doit(1,$changed);
echo $changed;

Pass by reference: Not working with WordPress

The WordPress apply_filter and add_filter functions do not allow variable passing by reference. Therefore, the following code will not work.

function doit($in, &$var2){
    $var2=true;
    return $in+1;
}
 
add_filter('myfilter','doit',10,2);
$changed=false;
echo apply_filters('myfilter',1,$changed);
echo $changed;

Dirty solution

You could use $GLOBALS to overcome this problem. I would not recommend this method, as it's not flexible, not safe to re-use and requires the function and the main code to be synchronized.

function doit($in){
    global $changed;
    $changed=true;
    return $in+1;
}
 
add_filter('myfilter','doit');
$changed=false;
echo apply_filters('myfilter',1);
echo $changed;

The good solution

The correct solution to this problem, is to combine all variabled in one array, and use this array as the first variable.

Example 1: For a few parameters

function doit($in){
    list($in,$var2)=$in;
    $var2=true;
    return array($in,$var);
}
 
add_filter('myfilter','doit');
$changed=false;
list($in,$changed)=apply_filters('myfilter',array(1,$changed));
echo $in;
echo $changed;

Example 2: For more complex situations

function doit($in){
    $in['changed']=true;
    $in['in']+=1;
    return $in;
}
 
add_filter('myfilter','doit');
$changed=false;
$in=1;
extract(  apply_filters('myfilter',compact('in','changed'))  );
echo $in;
echo $changed;

This last method may impose a security risk if you use third party plugins.© GeekLabInfo
WordPress: Pass variables by reference with apply_filter is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to https://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (7 votes, average: 3.71 out of 5)
Loading...

WordPress spam filtering: improved.

On this WordPress blog, I'm running the WP Hashcash plugin to prevent spam. Recently, I've seen a lot more spam, I guess spambots now recognise WPHC encryption.

WPHC encryption could be upgraded to withstand spam again. But new bots will break new encryption. The biggest problem is that all blogs using WPHC use the same javascript to decode the key. If only you could be a liiiiittle different from other blogs, standard bots wouldn't have a chance.

My solution is to include a few filters in WPHC. This allows for weblog owners to write a tiny plugin to have slightly different antispam than other weblogs. For instance, at this moment, my extension is as simple as:

<?php
/*
Plugin Name: WPHC Extension
Plugin URI: https://www.geeklab.info/2010/04/wordpress-spam-filtering/
Description:
Author: GeekLab.info
Version: 1.0
Author URI: https://www.geeklab.info
License: GPL
*/
function wphc_jskey_ext($js){
for($i = 0; $i < count($js); $i++)
$js[$i]--;
return $js;
}
function wphc_getjs_ext($in){
return preg_replace(';//WPHC2;','wphc_data[i]=wphc_data[i]+1;',$in);
}
add_filter('wphc_jskey', 'wphc_jskey_ext');
add_filter('wphc_getjs', 'wphc_getjs_ext');
?>

You may use substraction, addition, xor, byte-swapping or any other method you like to improve security. The security is not so much what is done to the key, but that the routine is slightly different from other blogs.

Changes to WP Hashcash required for this to work:
Patch file (only changes)
Whole file© GeekLabInfo
WordPress spam filtering: improved. is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to https://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

Magento and safe mode

The e-commerce application magento, for some reason, expects to have a lot of permissions on every server. One thing I stumbled upon when trying to install magento, was the creation of /tmp/magento/var.

Since /tmp could be shared between all users, this may not be the safest way. That's why my servers don't allow access to /tmp, but have a personal /tmp-style directory instead.

I got the error:
[Thu Feb 04 21:24:21 2010] [error] [client 1.2.3.4] PHP Warning: file_exists() [function.file-exists]: open_basedir restriction in effect. File(/tmp/magento/var) is not within the allowed path(s): (/blah/blah/website.com:/usr/share/pear:/var/www/error) in /blah/blah/website.com/app/code/core/Mage/Core/Model/Config/Options.php on line 214

The fix is very, very easy. But since I couldn't find anyone else posting the exact fix, I thought I'd do it.

in app/code/core/Mage/Core/Model/Config/Options.php on line 137, you find:
public function getSysTmpDir()
{
return sys_get_temp_dir();
}

Change it to:
public function getSysTmpDir()
{
return $_SERVER['DOCUMENT_ROOT'].'/your_secret_tmp_dir/';
}
© GeekLabInfo
Magento and safe mode is a post from GeekLab.info. You are free to copy materials from GeekLab.info, but you are required to link back to https://www.geeklab.info

1 Star2 Stars3 Stars4 Stars5 Stars (2 votes, average: 3.00 out of 5)
Loading...