RSS
 

Archive for the ‘PHP’ Category

Setting the maximum execution time and memory limit when PHP is running in safe mode

24 May

Many php applications, like WordPress Backup to Dropbox, require an extended max execution time and memory limit PHP settings in order to complete a task. By default the time setting is set to 30 seconds and, in the case of my WordPress plugin, is not enough for a backup to be completed.

If the PHP installation was not compiled in safe mode then a developer can temporarily change this value within a plugin using set_time_limit. So for any long running scripts setting the time limit to zero will tell PHP to allow the script to run forever.

However if your PHP installation is running in safe mode, this functionality is blocked and there is no way of altering the time or memory limit from within the application. Therefore the only way to get the an application to complete its task the php.ini max_execution_time and memory_limit setting will need to be altered. In the case of WordPress Backup to Dropbox this setting needs to be set to at least 3600 seconds  (1 hour) and at least 150M respectively.

How easily this value can be changes depends on how your hosts PHP installation is configured. If your host allows it you can put a file named php.ini inside the root and wp-admin folders of your WordPress installation with the settings set to

max_execution_time = 0
memory_limit = 150M

If this does not work then you have to edit the value in your php.ini file. The location of this file depends on your operating system and a quick Google search will yield plenty of literature on how this is done.

 

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