RSS
 

Posts Tagged ‘PHP’

WordPress Backup to Dropbox 0.7.1

08 May

I have released a new version of the WordPress Backup to Dropbox plugin that will hopefully alleviate manny of the issues that some users are experiencing.

The biggest problem reported was an issue where the backup starts but does not complete. There is no error, zip archive and no upload to Dropbox which is a rather large issue considering that that is the sole purpose of this plugin!

After some investigation I have concluded that the issue is to do with the amount of memory available to the PHP process and the fact that zipping and uploading large files can be memory intensive.

The original zipping algorithm was inefficient and attempted to zip the entire website in memory before writing to disk. This worked fine in local testing and on my blog because my total website size is around 10 megabytes and the PHP memory limit setting was set to 98 megabytes. So she had plenty of padding to get the job done!

Unfortunately this is not the case for many of you so I have re-engineered the zipping algorithm to take into account PHP’s memory limit setting. Now, when the zip archive is created, it will write to disk when we reach half of the set memory limit. In addition, when it encounters a file that is larger then what can be put into memory it will attempt to increase the memory limit accordingly.

The biggest issue here is the fact that many shared hosting providers, like the one that mikeyd.com.au is hosted on, do not allow you to alter the memory limit PHP ini setting, any attempt to do so will yield an error. This means that for users in the same situation, at this point in time, it is not possible to zip a file that is over half of the PHP memory limit setting. So, on my server with a memory limit of 98 megabytes, the largest individual file that I can add to the archive is approximately 49 megabytes.

This problem also extends to the upload process. The PEAR OAuth upload process uses a significant amount of memory to perform an upload. After a fair bit of testing I came to the conclusion that it requires a PHP memory limit of 2.5 times the size of the file. So, for my server setup, the maximum backup I can upload is approximately 42 megabytes. This is far from optimal and I plan to investigate this further.

For the people who have more control over their servers you might find it more efficient to use the native PHP OAuth extension that can be compiled and installed via PECL. Once installed and activated on your server you can make the plugin use it by changing the class Dropbox_OAuth_PEAR to Dropbox_OAuth_PHP on line 56 of class-dropbox-facade.php. But please note that I have not tested this at all.

So there you have it! Hopefully this release will just work for most of you. Over the coming weeks I plan add the ability to choose which folders you wish to include/exclude in the backup that will also aid in getting the backup size down.

If you haven’t already done so browse to the WordPress plugin directory and install WordPress Backup to Dropbox 0.7.1.

Thanks again for the feedback!

If you notice any more issues or want to request a feature please do so on the BitBucket issue tracker.

 

How to use PHP’s ReflectionClass to test private methods and properties with PHPUnit

20 Jan

The other day I stumbled across PHP’s ReflectionClass that is available in version 5.3.2 or newer. It is a fantastic tool that allows you to grab information about a class and, in turn, any of its runtime objects. So, when you couple it with with PHPUnit you can easily use it to test private and protected methods and functions of any class.

Up until now, I have always found this to be a predicament in any programming language. You have a lovely class that follows all the rules of object oreiented programming, including encapsualtion and information hiding, that only exposes a small number of methods to the public. In many cases, to keep your code DRY, these public methods rely on private methods to perform task that is very specific to the class and is of no use in the public domain.

So, how do you individually test these private methods of your class without making them public? Well as you may have guessed… PHP’s ReflectionClass is one way of doing so!

The class below is good example, it has the public method validateData that relies on functionality of the constructor, where the incoming data is sorted, and the checkValue method, that ensures that the is a number between 5 and 10.

class Foo {

	private $data = array();

	/**
	 * Creates a new Foo object by taking an array of items
	 * and sorting it before setting the data property
	 * @param  $data
	 */
	function __construct($data) {
		sort($data);
		$this->data = $data;
	}

	/**
	 * Checks whether a value is between 5 and 10
	 * @param  $value
	 * @return bool
	 */
	private function checkValue($value) {
		if ($value && $value > 5 && $value < 10) {
			return true;
		}
		return false;
	}

	/**
	 * Validates the data of this class's data to ensure that all
	 * its values are sorted and between 5 and 10
	 * @return bool
	 */
	public function validateData() {
		$is_valid = true;
		$prev_value = 0;
		foreach ($this->data as $value) {
			if (!$this->checkValue($value) || $prev_value > $value) {
				$is_valid = false;
				break;
			}
			$prev_value = $value;
		}
		return $is_valid;
	}
}

Finally the PHPUnit class below is a comprehensive set of tests for the above class, it uses the ReflectionClass in each of our tests:

  • To verify that our constructor is correctly sorting the incoming array by extracting the private class property ‘data’ and checking that it is, in fact, sorted.
  • To test the private checkValue method to make sure that it conforms to our rules
  • Finally, to test the validateData method with an invalid (not sorted) array to verify it correctly returns false
class DataTest extends PHPUnit_Framework_TestCase {

	/**
	 * Foo::$data is private so lets php reflection
	 * class to test it
	 * @return void
	 */
	public function testConstructor() {
		//First we need to create a ReflectionClass object
		//passing in the class name as a variable
		$reflection_class = new ReflectionClass("Foo");

		//Then we need to get the property we wish to test
		//and make it accessible
		$property = $reflection_class->getProperty('data');
		$property->setAccessible(true);

		//We need to create an empty object to pass to
		//ReflectionProperty's getValue method
		$foo = new Foo(array(7, 6, 8));

		$this->assertEquals(array(6, 7, 8), $property->getValue($foo));
	}

	/**
	 * Foo::checkValue is private so lets php reflection
	 * class to test it
	 * @return void
	 */
	public function testCheckValue()
    {
		$reflection_class = new ReflectionClass("Foo");

		//Then we need to get the method we wish to test and
		//make it accessible
		$method = $reflection_class->getMethod("checkValue");
		$method->setAccessible(true);

		//We need to create an empty object to pass to
		//ReflectionMethod invoke method followed by our
		//test parameters
		$foo = new Foo(null);

		//Boundary test - False expected
		$this->assertFalse($method->invoke($foo, 5));

		//Good data - True Expected
		$this->assertTrue($method->invoke($foo, 7));
    }

	/**
	 * validateData relies on checkValue and the constructor.
	 * So now that, from the tests above we know that these two
	 * work as expected we can test it!
	 * @return void
	 */
    public function testValidateData()
    {
		$foo = new Foo(array(6, 7, 8 ,9));
		$this->assertTrue($foo->validateData());

		$foo = new Foo(array(10));
		$this->assertFalse($foo->validateData());

		//We may also want to test to confirm our rule that
		//the array must be sorted here.

		$reflection_class = new ReflectionClass("Foo");

		//Then we need to get the property we wish to modify,
		//set it to accessible and then override its value
		//with an invalid one
		$property = $reflection_class->getProperty('data');
		$property->setAccessible(true);
		$property->setValue($foo, array(7, 9, 8));

		$this->assertFalse($foo->validateData());
    }
}

Now because each individual method is tested you can easily pinpoint any errors that may be introduced as the code evolves. Obviously this is overkill for a simple class like this, however, you may have more complicated private methods that provide some crucial functionality to a public method that should be individially tested.

 
3 Comments

Posted in PHP, Testing

 

Cross browser PHP drop down menu generator powered by JQuery and CSS.

15 May

I needed to create a drop down menu that supported all the major browsers that was generated with dynamic content. So I decided to use the tried and true unordered HTML list approach. This approach can be easily controlled with pure CSS in browsers like Chrome and Firefox, however, other browsers such as Internet Explorer cause issues so JQuery is required to force compliance across multiple platforms and browsers.

First I created this neat little class that can be used to create an object model of MenuItems that can be later serialized into a HTML unordered list. This model is basically a linked list of MenuItems where the serialize function just iterates through each object and its children converting its properties into a string.

class MenuItem {

    private $name;
    private $url;
    private $level;
    private $items;

    public function __construct($item_name, $item_lvl, $item_url = "#") {
        $this->name = $item_name;
        $this->url = $item_url;
        $this->level = $item_lvl;
        $this->items = array();
    }

    public function add_item(MenuItem $menu_item) {
        $this->items[] = $menu_item;
    }

    public function serialize() {
	$html = "";

        if ($this->level == 0) {
            $html = "<ul class=\"menu\">\n";
        }

        if (!empty($this->items)) {
            $html .= "<li class=\"{$this->get_class()} menu_arrow\">";
        } else {
            $html .= "<li class=\"{$this->get_class()}\">";
        }

        $html .= "<a href=\"$this->url\">$this->name";

        if (!empty($this->items)) {
            $html .= "</a>\n<ul class=\"{$this->get_class()}_block\">\n";
            foreach ($this->items as $menu_item) {
                $html .= $menu_item->serialize();
            }
            $html .= "</ul>\n";
        } else {
            $html .= "</a>";
        }

        $html .= "</li>\n";

        if ($this->level == 0) {
            $html .= "</ul>\n";
        }

        return $html;
    }

    private function get_class() {
        switch ($this->level) {
            case 0:
                $class = "level_zero";
                break;
            case 1:
                $class = "level_one";
                break;
            case 2:
                $class = "level_two";
                break;
        }
        return $class;
    }
}

This class makes it very easy to dynamically generate a multi tiered menu. All you have to do is create your base items and add them to the MenuItem that they belong too.

$search_links = new MenuItem("Search", 1);
$search_links->add_item(
        new MenuItem("Google", 2, "http://www.google.com")
);
$search_links->add_item(
        new MenuItem("Yahoo", 2, "http://www.yahoo.com")
);

$social_links = new MenuItem("Social", 1);
$social_links->add_item(
        new MenuItem("Facebook", 2, "http://www.facebook.com")
);
$social_links->add_item(
        new MenuItem("Twitter", 2, "http://www.twitter.com")
);

$menu = new MenuItem("Links", 0);
$menu->add_item($search_links);
$menu->add_item($social_links);

echo $menu->serialize();

The code above generates the unordered list below which, as mentioned before, can be controlled with pure CSS in the newer standards compliant browsers.

<ul class="menu">
<li class="level_zero menu_arrow"><a href="#">Links</a>
<ul class="level_zero_block">
<li class="level_one menu_arrow"><a href="#">Search</a>
<ul class="level_one_block">
<li class="level_two"><a href="http://www.google.com">Google</a></li>
<li class="level_two"><a href="http://www.yahoo.com">Yahoo</a></li>
</ul>
</li>
<li class="level_one menu_arrow"><a href="#">Social</a>
<ul class="level_one_block">
<li class="level_two"><a href="http://www.facebook.com">Facebook</a></li>
<li class="level_two"><a href="http://www.twitter.com">Twitter</a></li>
</ul>
</li>
</ul>
</li>
</ul>

The list above is controlled with the tiniest amount of CSS below. Of course the nicer you wan’t your menu to look the more CSS you will need to throw in!

ul.menu li ul {
	display: none;
}

The JQuery code I used to control the above menu is larger then it needs to be in order to make the menu support most browsers and operating systems. Many of the hacks in the script is to force Internet Explorer 6/7 to conform to the likes of Chrome and Firefox. Only the min width value needs to be set here to get your menu pop outs positioned correctly.

/* IE does not support min-width so we can get it with js since we are
 * already iterating through the items to display them.
 */
function setMinWidth(element) {
	if (element.width() < 150) {
		element.css('width', '150px')
	}
}

/* IE positoning is kinda random compared to FF, Chrome and Safari so
 * this is to force it to conform.
 */
function positionPopout(element, top) {
	element.css('display', 'block');
	element.css('top', top + "px");
	setMinWidth(element);
}

$(document).ready(function() {
	$('li.level_zero').hover(
		function() {
			var element = $('ul.level_zero_block', this);
			var top = $(this).offset().top + $(this).height();

			//Fix IE left
			element.css('left', ($(this).position().left + 2) + "px");
			positionPopout(element, top);
		},
		function() {
			$('ul.level_zero_block', this).css('display', 'none');
		}
	);

	$('li.level_one').hover(
		function() {
			var element = $('ul.level_one_block', this);
			var top = $(this).offset().top -  + $(this).height();

			positionPopout(element, top);
			setMinWidth(element);
		},
		function() {
			$('ul.level_one_block', this).css('display', 'none');
		}
	);

	$('li.level_two').hover(
		function() {
			var element = $('ul.level_two_block', this);
			var top = $(this).offset().top - ($(this).height() * 2);

			positionPopout(element, top);
			setMinWidth(element);
		},
		function() {
			$('ul.level_two_block', this).css('display', 'none');
		}
	);
});

This way of providing a drop down menu for your website is not a new idea, however I think using the MenuItem class is an elegant and easy way of dynamically generating this style of menu.

 
2 Comments

Posted in JQuery, PHP