Linux uptime

If you want to show the uptime of your linux server on your website, you can do so very easily.

<?php
function linuxUptime() {
  $ut = strtok( exec( "cat /proc/uptime" ), "." );
  $days = sprintf( "%2d", ($ut/(3600*24)) );
  $hours = sprintf( "%2d", ( ($ut % (3600*24)) / 3600) );
  $min = sprintf( "%2d", ($ut % (3600*24) % 3600)/60  );
  $sec = sprintf( "%2d", ($ut % (3600*24) % 3600)%60  );
  return array( $days, $hours, $min, $sec );
}

$ut = linuxUptime();
// If you would like to show the seconds as well just add [ , $ut[3] seconds ] after minutes.
echo "Time since last reboot: $ut[0] days, $ut[1] hours, $ut[2] minutes";
?>

Just call the $ut = linuxUptime() function and then you can use the variables to show the time.

**NOTE: Your server must allow you to run the exec() PHP command. Some hosts disable the execution of this and several other PHP functions.

Now if you were wanting to gather the uptime of multiple servers all at the same time this can be accomplished with CURL. What we would end up doing is using the above code and place it in a PHP file on each of the target servers. In the example below you will see I am referencing a file called linuxUptime.php which holds the code listed above. We could then use a MySQL database or just an array full of domain names that we would loop through to gather the stats. Below I am posting a simple script which uses an array as an example. (This file does not currently exist on my site to show uptime of my site)

<?php
$sites = array('danielkassner.com'); // Create a list of sites to check
foreach($sites as $site) { // Loop through each site and get uptime

$ch = curl_init(); // Initiate curl session
curl_setopt($ch, CURLOPT_URL, 'http://'.$site.'/linuxUptime.php'); // Set the URL of the uptime script
curl_setopt($ch, CURLOPT_HEADER, 0); // Disable header output
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // Return data as a string instead of output directly
$data=curl_exec($ch); // Execute curl commands
curl_close ($ch); // Close the curl session

echo $site.': '.$data.'<br />'; // Output value returned from the linuxUptime.php file
} // End server loop
?>

When we gather stats like this we could easily store the uptime values in a database table so that we could track the history.

Enjoy!

Notepad++ Ctrl+Tab tip

If you are like me and prefer to use the keyboard as much as possible instead of a mouse you will like this tip. When in Notepad++ if on your keyboard you press Ctrl+Tab it brings up a Windows style Alt+Tab menu to cycle through your open documents. When you let up on the keys it switches to the file you selected. Check out the screenshot below of it in action.

Notepad++Trick

Feature request for Notepad++ Function List plugin

As the number of visitors continues to increase to my Notepad++ Function List for PHP development post I have frequently been asked if this plugin can do a certain task. This task would be to add multiple rules to one main category. So for instance you have a file that has multiple classes located in it and each class has its own set of variables and functions. The Function List plugin allows us to parse these out and find them. However, in its current state we can only link one parsing rule to another.

Example:
Current State:
-Classes
–Training model extends Model
—Functions
—-__construct
—-EventListing
-Class Variables
–$Month
–$Day
–$Year

What we would like:
-Classes
–Training model extends Model
—Class Variables
—-$Month
—-$Day
—-$Year
—Functions
—-__construct
—-EventListing

I have sent an email to the creator of the plugin(Jens Lorenz) about asking the possibility of changing the plugin and that correspondence is listed below:

Sent from Me on March 17, 2010 7:57 AM

I have used the Function List plugin for Notepad++ for some time now and really enjoy it. My question to you is if it would be possible to add multiple subgroups under one group? For instance I am a PHP developer; I have parsing rules for Classes, Class Variables and Functions. I would love to be able to put Class Variables along with the Functions rules under the classes tree. So instead of having:
-Classes
–printer extends resources
—Functions
—-__construct
—-sqlInsert
-Class Variables
–$security
–$db

I would have:
-Classes
–printer extends resources
—Class Variables
—-$security
—-$db
—Functions
—-__construct
—-sqlInsert

I have put up a blog posting of what my current FunctionListRules.xml section looks like at: http://www.danielkassner.com/2010/01/22/using-notepads-function-list-plugin-for-php-development

If you have any ideas that would be great. Thanks!

Sent by Jens Lorenz on March 18, 2010 at 3:27 AM

Hello Daniel,

currently it isn’t possible. Only one level of subgrouping is possible at the moment.

Best Regards
Jens

Sent by me on March 18, 2010 at 7:41 AM

Do you think that this desired functionality will or could be added to a future release? I am sure that it will take some time to accomplish but it would be nice.

Thank you for the quick response.

I did not get a response back from that last email. I wish that I knew more about C++ to modify and send the changes I would make to him for everyone else to enjoy. I am sure he is a busy man just like me which is why I probably did not get a response back.

If you would like to see this feature potentially get added please contact him via email and or post comment here on this posting. You can find his email by opening Notepad++, selecting the Plugins > Function List > Help menu item.

Using Notepad++’s Function List plugin for PHP development

One thing I really love about Notepad++ is the plugin’s that are available. One of such plugins that I enjoy is the Function List plugin to automatically search my code to pull classes, functions and much more into an easy to see pane on the right side of my screen. I had previously posted tutorials on another site but now I have made the process for “installing” these new rules easier by posting the XML as well as adding more features. Once you have followed the below steps the Function List plugin will show all of the following:

  • PHP classes
  • PHP class variables – (public, protected and private)
  • PHP functions – already does this by default
  • CodeIgniter Views
  • CodeIgniter Helpers
  • CodeIgniter Libraries
  • CodeIgniter Models
  • PHP include()
  • PHP include_once
  • PHP require()
  • PHP require_once()

Update: I updated the instructions based on a comment below to close Notepad++ while editing the .xml file

Step 1: Close Notepad++
Step 2: Navigate to C:\Program Files\Notepad++\plugins\Config – This is the default installation folder, it may be different on your system.
Step 3: Open the FunctionListRules.xml file in your favorite editor other than Notepad++. The settings may not save if you open this file in Notepad++.
Step 4: Do a search for the following line: (This will more than likely be at the end of the file.)

<Language name="PHP" imagelistpath="">

Step 5: Add the following code between the opening and closing Language tags:

<Group name="Classes" subgroup="Functions" icon="0" child="0" autoexp="4" matchcase="1" fendtobbeg="" bbegtobend="\{" keywords="">
            <Rules regexbeg="class" regexfunc="[\w_ ]+" regexend="" bodybegin="\{" bodyend="\}" sep="" />
        </Group>
        <Group name="Class Variables" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg="public\ " regexfunc="\$.*[^;]" regexend=".*;" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg="protected\ " regexfunc="\$.*[^;]" regexend=".*;" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg="private\ " regexfunc="\$.*[^;]" regexend=".*;" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Functions" subgroup="" icon="0" child="0" autoexp="4" matchcase="1" fendtobbeg="" bbegtobend="\{" keywords="">
            <Rules regexbeg="function[\s&amp;]+" regexfunc="[\w_]+" regexend="\s*\(.*\)" bodybegin="\{" bodyend="\}" sep=";" />
        </Group>
        <Group name="CodeIgniter Views" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='\$this-&gt;(.*)load-&gt;view\([&apos;&quot;]' regexfunc='[&quot;\/\w_ ]+' regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="CodeIgniter Helpers" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg="\$this-&gt;(.*)load-&gt;helper\(array\(" regexfunc='[&apos;,&quot;\w_ ]+' regexend="" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg='\$this-&gt;(.*)load-&gt;helper\([&apos;&quot;]' regexfunc='[&quot;\w_]+' regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="CodeIgniter Libraries" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg="\$this-&gt;(.*)load-&gt;library\(array\(" regexfunc='[&apos;,&quot;\w_ ]+' regexend="" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg='\$this-&gt;(.*)load-&gt;library\([&apos;&quot;]' regexfunc='[&quot;\w_]+' regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="CodeIgniter Models" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg="\$this-&gt;(.*)load-&gt;model\(array\(" regexfunc='[&apos;,&quot;\w_ ]+' regexend="" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg='\$this-&gt;(.*)load-&gt;model\([&apos;&quot;]' regexfunc='[&quot;\w_]+' regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Include" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='include\([&apos;&quot;]' regexfunc="*.*[\w]" regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Include Once" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='include_once\([&apos;&quot;]' regexfunc="*.*[\w]" regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Require" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='require\([&apos;&quot;]' regexfunc="*.*[\w]" regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Require Once" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='require_once\([&apos;&quot;]' regexfunc="*.*[\w]" regexend="" bodybegin="" bodyend="" sep="" />
        </Group>

My full section including the Language tags looks like this:

<Language name="PHP" imagelistpath="">
        <CommList param1="#" param2="" />
        <CommList param1="//" param2="" />
        <CommList param1="/\*" param2="\*/" />
        <Group name="Classes" subgroup="Functions" icon="0" child="0" autoexp="4" matchcase="1" fendtobbeg="" bbegtobend="\{" keywords="">
            <Rules regexbeg="class" regexfunc="[\w_ ]+" regexend="" bodybegin="\{" bodyend="\}" sep="" />
        </Group>
        <Group name="Class Variables" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg="public\ " regexfunc="\$.*[^;]" regexend=".*;" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg="protected\ " regexfunc="\$.*[^;]" regexend=".*;" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg="private\ " regexfunc="\$.*[^;]" regexend=".*;" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Functions" subgroup="" icon="0" child="0" autoexp="4" matchcase="1" fendtobbeg="" bbegtobend="\{" keywords="">
            <Rules regexbeg="function[\s&amp;]+" regexfunc="[\w_]+" regexend="\s*\(.*\)" bodybegin="\{" bodyend="\}" sep=";" />
        </Group>
        <Group name="CodeIgniter Views" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='\$this-&gt;(.*)load-&gt;view\([&apos;&quot;]' regexfunc='[&quot;\/\w_ ]+' regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="CodeIgniter Helpers" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg="\$this-&gt;(.*)load-&gt;helper\(array\(" regexfunc='[&apos;,&quot;\w_ ]+' regexend="" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg='\$this-&gt;(.*)load-&gt;helper\([&apos;&quot;]' regexfunc='[&quot;\w_]+' regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="CodeIgniter Libraries" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg="\$this-&gt;(.*)load-&gt;library\(array\(" regexfunc='[&apos;,&quot;\w_ ]+' regexend="" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg='\$this-&gt;(.*)load-&gt;library\([&apos;&quot;]' regexfunc='[&quot;\w_]+' regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="CodeIgniter Models" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg="\$this-&gt;(.*)load-&gt;model\(array\(" regexfunc='[&apos;,&quot;\w_ ]+' regexend="" bodybegin="" bodyend="" sep="" />
            <Rules regexbeg='\$this-&gt;(.*)load-&gt;model\([&apos;&quot;]' regexfunc='[&quot;\w_]+' regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Include" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='include\([&apos;&quot;]' regexfunc="*.*[\w]" regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Include Once" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='include_once\([&apos;&quot;]' regexfunc="*.*[\w]" regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Require" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='require\([&apos;&quot;]' regexfunc="*.*[\w]" regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
        <Group name="Require Once" subgroup="" icon="0" child="0" autoexp="4" matchcase="0" fendtobbeg="" bbegtobend="" keywords="">
            <Rules regexbeg='require_once\([&apos;&quot;]' regexfunc="*.*[\w]" regexend="" bodybegin="" bodyend="" sep="" />
        </Group>
    </Language>

Step 6: Save and close, then open up a PHP file in Notepad++ to see if it shows the desired output in the Function List tool.

Notepad++ upgrade

At work my main workstation is a Microsoft Vista box. I do most of my development in Notepad++ and a little bit in PSPad. I had previously been running an older version of Notepad++ (v5.4.5 UNICODE to be exact) and I was upgrading to v5.6.4 UNICODE. Here are a few things to keep in mind when upgrading:

  • Windows Vista: Give your user login full permissions to the c:\Program Files\Notepad++ folder. This allows you to make theme changes and other changes in the system and have those changes get saved automatically.
    • Open My Computer and navigate to c:\Program Files
    • Right click on Notepad++ folder and go to Properties
    • Select the Security tab and click the Edit button
    • Click Add and search for your name
    • Once you have added your name click on it under Group or user names
    • Check the Full control allow checkbox and click OK on the remaining properties boxes.
  • If you use the Function List plugin make sure you visit here and download the FunctionList20091109_dll.zip file and place this .dll in the plugins folder (c:\Program Files\Notepad++\plugins\). This download is compatible with the Unicode version of Notepad++ 5.5 +.

Calculate users age with PHP

Recently I needed some code to calculate a users age based on their birthday. There are many different functions that are already created out there that I could have used, but instead I wrote this piece of code. It uses PHP 5 DateTime class to return an array of information pertaining to how old a person is. By default if you leave the second parameter off it will calculate the difference from the start date to the current day. If you are trying to calculate how old somebody was when they had passed away or how old they were on a certain date you can pass the second parameter. There are several different checks in this code snippet to make sure you are using a valid date for the start and end date.

This function requires dates to be passed in standard: YYYY-MM-DD format
Code:

<?php
if (!function_exists('calculate_age')) {
        /*
        Author: Daniel Kassner
        Website: http://www.danielkassner.com
        */
	// Checked this function against http://www.timeanddate.com/date/duration.html

	function calculate_age($startdate = '0000-00-00', $enddate = '0000-00-00') {
		
		// Check to see if start date is valid

		@list($year, $month, $day) = explode('-', $startdate);
		if (@!checkdate($month,$day,$year)) {
			return false;
		}
		
		// Create a new datetime object to do our calculations with
		$s = new DateTime($startdate);
		// We have to have an end date so if it is empty or 0000-00-00 we will make it right now
		if (empty($enddate) OR $enddate == '0000-00-00') {
			$enddate = 'now';
		} else {
			// Check to see if end date is valid

			@list($year, $month, $day) = explode('-', $enddate);
			if (@!checkdate($month,$day,$year)) {
				return false;
			}
		}
		// Create a new datetime object to compare as an end date
		$e = new DateTime($enddate);
		
		if ($s->format('Ymd') > $e->format('Ymd')) {
			// End date cannot be before start date
			return false;
		}
		
		// Calculate our base numbers here
		$years = $e->format('Y')-$s->format('Y');
		$months = $e->format('m')-$s->format('m');
		$days = $e->format('d')-$s->format('d');

		// We cannot have negative days
		// Calculate how many days are in the startdate month
		// subtract the startdate day and add 1
		// Then add back in the day of the enddate
		// Subtract 1 month
		if ($days < 0) {
			$days = $s->format('t')-$s->format('d')+1;
			$days += $e->format('d');
			$months--;
		}
		
		// We cannot have negative months
		// Subtract 1 year and add back 12 months to make months positive
		if ($months < 0) {
			$years--;
			$months += 12;
		}

		return array('years'=>$years,'months'=>$months, 'days'=>$days);
	}
}
?>

Usage:

<?php
// Current date is 2010-01-19
$birthday = '1987-09-23';
$age = calculate_age($birthday);
var_dump($age);
echo '<hr />';
$startdate = '1985-09-06';
$enddate = '1987-09-23';
$difference = calculate_age($startdate, $enddate);
var_dump($difference);
?>

Output:

array(3) { ["years"]=> int(22) ["months"]=> int(3) ["days"]=> int(27) }
——————————————————————————————————–
array(3) { ["years"]=> int(2) ["months"]=> int(0) ["days"]=> int(17) }

Creating a CSV file with PHP

While working on several coding projects I find myself needing to export data in CSV format. All this basically means is a text file with many lines of text separated by commas(,) which can then be opened up in a spreadsheet application or imported into another program. So for an example you have the following saved in a file called export.csv:

first value, second value, third value
fourth value, fifth value, sixth value

Every value before a comma is a new cell in the spreadsheet and everything after each new line is the start of a new row. Which means that the above values would produce something like the following in a spreadsheet application:

first value second value third value
fourth value fifth value sixth value

To accomplish this in PHP you can use arrays, joins and a few header functions to download the file. You could also save this output to a file instead of forcing the browser to download the content.

<?php
$row = array();
$row[] = 'first value';
$row[] = 'second value';
$row[] = 'third value';
$data .= join(',', $row)."\n"; // Join all values without any trailing commas and add a new line

$row = array(); // We must clear the previous values
$row[] = 'fourth value';
$row[] = 'fifth value';
$row[] = 'sixth value';
$data .= join(',', $row)."\n";

// Output the headers to download the file
header("Content-type: application/x-msdownload");
header("Content-Disposition: attachment; filename=log.csv");
header("Pragma: no-cache");
header("Expires: 0");
echo $data;
?>

Notice the join function adding the commas between the values and then finally adding the new line with the \n before finally outputting the data as a downloadable file.

Now you may be noticing one problem with the above code. Sure the code works but what happens if there is a comma, quote or new line in one of the $row variables? If you tried to put a comma between the first and value in our first value like:

first, value, second value, third value
fourth value, fifth value, sixth value

You would get:

first value second value third value
fourth value fifth value sixth value

Obviously not the output we were looking for. To fix this you have to escape the commas and new lines with quotes like:

"first, value", second value, third value
fourth value, fifth value, sixth value

Now if you are wanting to use quotes in your CSV file you have to escape those with double quotes such as:

"""first"" value", second value, third value
fourth value, fifth value, sixth value

Now that you know the above information about escaping values you can use the below function to escape all of the values before joining them with commas.

<?php
/*
Created by: Daniel Kassner
Website: http://www.danielkassner.com
*/
function escape_csv_value($value) {
	$value = str_replace('"', '""', $value); // First off escape all " and make them ""
	if(preg_match('/,/', $value) or preg_match("/\n/", $value) or preg_match('/"/', $value)) { // Check if I have any commas or new lines
		return '"'.$value.'"'; // If I have new lines or commas escape them
	} else {
		return $value; // If no new lines or commas just return the value
	}
}
?>

Usage:

<?php
$SafeValue = escape_csv_value('your value here');
?>

Now you may also be wondering about an easy way to export data straight from your MySQL database into a CSV file for download. Using some basic PHP functions for working with databases we can easily create a new export based on the query you run. To change the export just change the query that you run.

<?php
$db = mysql_connect('localhost', 'user', 'password'); // Connect to the database
$link = mysql_select_db('database name', $db); // Select the database name

/*
Created by: Daniel Kassner
Website: http://www.danielkassner.com
*/
function escape_csv_value($value) {
	$value = str_replace('"', '""', $value); // First off escape all " and make them ""
	if(preg_match('/,/', $value) or preg_match("/\n/", $value) or preg_match('/"/', $value)) { // Check if I have any commas or new lines
		return '"'.$value.'"'; // If I have new lines or commas escape them
	} else {
		return $value; // If no new lines or commas just return the value
	}
}

$sql = mysql_query("SELECT * FROM tablename"); // Start our query of the database
$numberFields = mysql_num_fields($sql); // Find out how many fields we are fetching

if($numberFields) { // Check if we need to output anything
	for($i=0; $i<$numberFields; $i++) {
		$keys[] = mysql_field_name($sql, $i); // Create array of the names for the loop of data below
		$head[] = escape_csv_value(mysql_field_name($sql, $i)); // Create and escape the headers for each column, this is the field name in the database
	}
	$headers = join(',', $head)."\n"; // Make our first row in the CSV
	
	$data = '';
	while($info = mysql_fetch_object($sql)) {
		foreach($keys as $fieldName) { // Loop through the array of headers as we fetch the data
			$row[] = escape_csv_value($info->$fieldName);
		} // End loop
		$data .= join(',', $row)."\n"; // Create a new row of data and append it to the last row
		$row = ''; // Clear the contents of the $row variable to start a new row
	}
	// Start our output of the CSV
	header("Content-type: application/x-msdownload");
	header("Content-Disposition: attachment; filename=log.csv");
	header("Pragma: no-cache");
	header("Expires: 0");
	echo $headers.$data;
} else {
	// Nothing needed to be output. Put an error message here or something.
	echo 'No data available for this CSV.';
}
?>

Please note that the above code also puts in a header row of what each of the columns is based on the database table fields. You can change what the headings are in your MySQL query by using the SQL as syntax. Examples:

SELECT fname, minitial, lname FROM users

Could be changed to:

SELECT fname as 'First Name', minitial as 'Middle Initial', lname as 'Last Name' FROM users

This would produce the desired output quickly and easily with a single MySQL query.

Enjoy working with CSV files that are properly escaped.

Quick way to download Flickr images

So I was browsing around on Flickr.com and found some images I wanted to save to my computer. The problem is that when you right click on an image you get a file called spaceball.gif which “covers” up the image from right click to save the image file. To get around this you will need the following:

  • Firefox
  • Adblock Plus

Once you have installed the Adblock Plus extension into Firefox follow the steps below:

  • Navigate to Flickr page that you want to save the image.
  • Right click the image you want to save and select Save Image As. If the filename is called spaceball.gif cancel the download
  • Right click on the image and select Adblock Plus: Block Image
  • Select the very first option under the Look for pattern which will more than likely be: |http://l.yimg.com/g/images/spaceball.gif and click Add Filter
  • Refresh page and try saving picture again

Enjoy saving images from Flickr when there is no option to download larger files.

Switch to our mobile site