Fizz Buzz and Fibbonacci combined

May 11th, 2017

I had a job interview recently and I was asked to do FizzBuzz.

The code is very simple to write, however I wanted to see if I could make it easily accept any series of numbers and easily alter its output.

The code I came up within an hour or so is below, but its use comes down to the simple one liners;

// Simple demo of numbers 0-5, default behaviour, no args
foreach(NumbersDirector::create() AS $number) echo "$number,";

Output: 0, 1, 2, 3, 4, 5

// Fizz Buzz from 1-100 using fizzbuzz factory builder
foreach(NumbersDirector::create(new NumericalSeries(array('start'=>1,'end'=>100)),new FizzBuzzBuilder()) AS $number) echo "$number,";

Output: 1,2,Fizz,4,Buzz,Fizz,7,8,Fizz,Buzz,11,Fizz,13,14,FizzBuzz,16,17,Fizz,19,Buzz,Fizz,22,23,Fizz,Buzz,26,Fizz,28,29,FizzBuzz,………………..

// Fibo from 0-2000
foreach(NumbersDirector::create(new FibbonacciSeries(array('end'=>2000))) AS $number) echo "$number,";

Output: 1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,

// Fibo from 2000-50000000 using fizzbuzz factory builder
foreach(NumbersDirector::create(new FibbonacciSeries(array('start'=>2000,'end'=>50000000)),new FizzBuzzBuilder()) AS $number) echo "$number,";

Output: Fizz,5998,9997,Buzz,Fizz,41987,67979,109966,FizzBuzz,287911,465856,753767,Fizz,Buzz,3193013,5166403,Fizz,13525819,Buzz,35411054,Fizz,

As you can see the last one is passing in a custom series and modifying the output to FizzBuzz.

It uses several patterns, ReadOnly, Factory, Director, Builder and returns an iterable instance, just a coding exercise really.

Full code below if anyone would care to see:

<?php
/*
Traits
*/
Trait Iterable{
 
	protected $_position;
    protected $_data;
 
    public function rewind() {
        $this->_position = 0;
    }
    public function current() {
        if ($this->valid()){
            $data = $this->getData();
            return $data[$this->_position];
        } 
 
    }
    public function key() {
        return $this->_position;
    }
    public function next() {
        ++$this->_position;
    }
    public function valid() {
        $data = $this->getData();
        return isset($data[$this->_position]);
    }
 
    protected function setData(array $data = null){
        $this->_data = $data;
        $this->rewind();
        return $this;
    }
 
    public function getData(){
 
        if (!isset($this->_data)){
            $this->setData();
        }
        return $this->_data;
    }
 
    public function getStart(){
 
        if (isset($this->_data[0])){
            return $this->_data[0];
        }
        return null;
    }
 
    public function getEnd(){
        $count = count($this->_data)-1;
        if ($count>0){
            return $this->_data[$count];
        }
 
        return null;
    }
 
    /*
     * Required by countable
     */
    public function count(){
        return count($this->_data);
    } 
}
 
trait Readonly{
 
 
    public function __construct(array $options = null)
    {     
        if (is_array($options)) {
            $this->setOptions($options);
        }
    }
 
    public function __set($name, $value)
    {
        $method = 'set' . $name;
        if (method_exists($this, $method)) {
            $this->$method($value);
            return $this;
        }
 
        throw new \Exception('"'.$name.'" is an invalid property of '.__CLASS__.' assignment of "'.$value.'" failed!');
 
    }
    public function __get($name)
    {
 
        $method = 'get' . $name;
        if (method_exists($this, $method)) {
            return $this->$method();
        }
 
        throw new \Exception('Invalid '.__CLASS__.' property '.$name);
    }
 
    public function setOptions(array $options)
    {
        $methods = get_class_methods($this);
        foreach ($options as $key => $value) {
            $method = 'set' . ucfirst($key);
            if (in_array($method, $methods)) {
                $this->$method($value);
            }
        }
        return $this;
    } 
} 
 
 
/*
Interfaces
*/
Interface SeriesInterface {
 
	public function generate();
}
 
Interface BuildersInterface {
 
	public function build($entry);
}
 
Interface ValueInterface {
    public function getValue();
    public function setValue();
    public function __toString();
}
 
/*
Abstract classes 
*/
abstract class Series implements SeriesInterface {
 
	use Readonly;
 
	protected $_start;
	protected $_end;
 
	public function setStart($start = 0){
		$this->_start = $start;
		return $this;
	}
 
	public function getStart(){
		if (!isset($this->_start)){
			$this->setStart();
		}
		return $this->_start;
	}
 
	public function setEnd($end = 5){
		$this->_end = $end;
		return $this;
	}
 
	public function getEnd(){
		if (!isset($this->_end)){
			$this->setEnd();
		}
		return $this->_end;
	}
 
	abstract function generate();
 
}
 
abstract class Value implements ValueInterface {
 
	use Readonly;
 
	protected $_val;
 
	public function getValue(){
        if (!isset($this->_val)){
            $this->setValue();
        }
        return $this->_val;
    }
    public function setValue($val = 0){
        if (!is_int($val)){
			throw new Exception('Expected integer as value got '.getType($val)); // would normally be the signature
		}
        $this->_val = $val;
        return $this;
    }
 
    abstract public function __toString();
 
}
 
/*
Classes
*/
class NumbersDirector implements Iterator{
 
	use Iterable;   
 
	protected function __construct(){}
	public function create(SeriesInterface $series = null, BuildersInterface $builder = null){
 
		if (is_null($series)){
			$series = new NumericalSeries();
		}
 
		if (is_null($builder)){
			$builder = new NumericalBuilder();
		}
 
		$stack = array();
 
		foreach($series->generate() AS $entry){
			$stack[]= $builder->build($entry);
		}
 
		$me = new self();
		$me->setData($stack); 
		return $me;
	}
 
}
 
class NumericalSeries extends Series {
 
	public function generate(){
 
		$series 	= array();
 
		for ($x=$this->start; $x<($this->end + 1); $x++){
			$series[] = $x;
		}
 
		return $series;
	}
}
 
class FibbonacciSeries extends Series {
 
 
    /**
     * Fibonacci using Binet's formula
     * @link http://mathworld.wolfram.com/BinetsFibonacciNumberFormula.html
     */
    public function binet($n)
    {
        $phi = (1 + sqrt(5)) / 2;
        return (pow($phi, $n) - pow(1 - $phi, $n)) / sqrt(5);
    }
 
    public function setStart($start = 1){
		$this->_start = $start;
		return $this;
	}
 
	public function setEnd($end = 55){
		$this->_end = $end;
		return $this;
	}
 
	public function generate(){
 
		$series 	= array();
		$fib 		= [$this->start,$this->start - 1];
		$next 		= 0;
		while($next < $this->end) {
		    $next = array_sum($fib);
		    array_shift($fib);
		    array_push($fib,$next);
		    $series[]=$next;
		}
		return $series;
	}
}
 
class NumericalBuilder implements BuildersInterface {
 
	public function Build($entry){
 
		$number 		=  new Number();
		$number->value 	= $entry;
		return $number;
	}
 
}
 
class FizzBuzzBuilder implements BuildersInterface {
 
	public function Build($entry){
 
		/* 
		Factory method
		*/
		$class 	= "";
 
		if ($entry%3==0){
			$class.= 'Fizz';
		}
 
		if ($entry%5==0){
			$class.= 'Buzz';
		}
 
		if (!class_exists($class) || !isset(class_implements($class)['ValueInterface'])){
			$class = "Number";
		}
 
		$number 		=  new $class();
		$number->value 	= $entry;
		return $number;
 
	}
 
}
 
class Number extends Value {
    public function __toString(){
		return (string) $this->getValue();
	}	
}
 
class Buzz extends Value {
	public function __toString(){
		return (string) 'Buzz';
	}
}
 
class Fizz extends Value {
	public function __toString(){
		return (string) 'Fizz';
	}
}
 
class FizzBuzz extends Value {
	public function __toString(){
		return (string) 'FizzBuzz';
	}
}
 
 
 
// Simple demo of numbers 0-5, default behaviour, no args
foreach(NumbersDirector::create() AS $number) echo "$number,";
echo "<hr />";
// Fizz Buzz from 1-100 using fizzbuzz factory builder
foreach(NumbersDirector::create(new NumericalSeries(array('start'=>1,'end'=>100)),new FizzBuzzBuilder()) AS $number) echo "$number,";
echo "<hr />";
// Fibo from 0-2000
foreach(NumbersDirector::create(new FibbonacciSeries(array('end'=>2000))) AS $number) echo "$number,";
echo "<hr />";
// Fibo from 2000-50000000 using fizzbuzz factory builder
foreach(NumbersDirector::create(new FibbonacciSeries(array('start'=>2000,'end'=>50000000)),new FizzBuzzBuilder()) AS $number) echo "$number,";
VN:F [1.9.9_1125]
Rating: 0.0/10 (0 votes cast)
VN:D [1.9.9_1125]
Rating: +1 (from 1 vote)
493 views

WordPress, concrete5, ZF2, PHP, mysql database dump

March 22nd, 2017

Here is a very simple script that once uploaded locks onto various architectures and extracts the database using the captured details.

For example, wordpress and concrete5 have been detected here:

Screenshot from 2017-03-22 11-18-40

When nothing is detected it will still offer the manual entering of the username and password.

Screenshot from 2017-03-22 11-18-47

It currently supports Concrete5 and WordPress, but I can easily upgrade it to support many more like ZF1, ZF2, Magento, Drupal, Joomla, etc, if there is any interest.

This is handy when you need to quickly copy a database, you simply upload this script to the doc_root and the script will attempt to handle the rest for you.

The script comes with password protection to prevent unauthorised usage, or it will not just be you downloading the database.

Screenshot from 2017-03-22 12-28-36

The script stores the username and password of those authorised to use it within the code, the password can be entered in plain text, or you can define your own algorithm and store the password encrypted in this way, within the code.

The script can be downloaded from github here and the full source code is below.

/*
 
 
Adrian Callaghan 21 Mar 2017 
 
Very lightweight database dumper that automatically locks access details provided by other PHP frameworks
 
 
 
****** How to use ******
 
Enter your usernames and passwords into the constructor in either plain text (insecure if read by someone else) or encypted
 
 
 
Example 1: allowing bob access with the password 1234 and joe access with password 5678 - no encryption 
 
	dbDump::Init(array(
		'users'	=> array(
			array('username'=>'bob','password'=>'1234'),
			array('username'=>'joe','password'=>'5678'),
		)));
 
 
 
Example 2: allowing bob access with the password 1234 and joe access with password 5678 - with encyption method and hashed passwords that must match the method result
 
	dbDump::Init(array(
		'users'	=> array(
			array('username'=>'bob','password'=>'81dc9bdb52d04dc20036dbd8313ed055'),
			array('username'=>'joe','password'=>'674f3c2c1a8a6f90461e8a66fb5550ba'),
		),
		'passwordEncryption'=>function($pass){
			return md5($pass);
		}
	));
 
*/
 
 
 
 
/******************
 
Constructor
 
*******************/
dbDump::Init(array(
	'users'	=> array(
		array('username'=>'bob','password'=>'81dc9bdb52d04dc20036dbd8313ed055'),
		array('username'=>'joe','password'=>'674f3c2c1a8a6f90461e8a66fb5550ba'),
	),
	'passwordEncryption'=>function($pass){
		return md5($pass);
	}
));
 
 
 
 
 
 
 
/******************
 
Class starts...
 
*******************/
final class dbDump{
 
	const APP_STATE = 'state';
	const APP_AUTH 	= 'MY_TOKEN';
	const APP_SALT  = 'MY_SALT';
 
	private $_users;
	private $_passwordEncryption;
 
	protected function destroySession(){
		$this->initSession();
		session_destroy();
		return $this;
	}
 
	protected function initSession(){
		if (session_status() == PHP_SESSION_NONE) {
		    session_start();
		}
 
		return $this;
	}
 
	protected function getSession($object = true){
		$this->initSession();
		return $object ? (object) $_SESSION : $_SESSION;
    }
 
   	protected function getSessionVar($var = ''){
   		return isset($this->session->{$var}) ? $this->session->{$var} : false;
    }
 
    protected function setSessionVar($key, $val){
    	$session 			= $this->session;
    	$session->{$key} 	= $val;
    	$this->session = (array) $session;
    }
 
    protected function setSession(array $values){
    	$this->initSession();
    	$_SESSION = $values;
    	return $this;
    }
 
	protected function getGet($object = true){
		return $object ? (object) $_GET : $_GET;
	}
 
	protected function getGetVar($var = ''){
   		return isset($this->post->{$var}) ? $this->post->{$var} : false;
    }
 
    protected function isPost(){
    	return empty($this->getPost(false)) ? false : true;
    }
 
	protected function getPost($object = true){
		return $object ? (object) $_POST : $_POST;
	}
 
	protected function getPostVar($var = ''){
   		return isset($this->post->{$var}) ? $this->post->{$var} : false;
    }
 
	protected function getState(){
		return $this->getSessionVar(self::APP_STATE);
	}
 
	protected function setState($state = ''){
		$this->setSessionVar(self::APP_STATE, $state);
		return $this;
	}
 
	protected function is_constant($token) {
	    return $token == T_CONSTANT_ENCAPSED_STRING || $token == T_STRING || $token == T_LNUMBER || $token == T_DNUMBER;
	}
 
	protected function strip($value) {
	    return preg_replace('!^([\'"])(.*)\1$!', '$2', $value);
	}
 
	protected function getDefinitions($php){
 
		$defines 	= array();
		$state 		= 0;
		$key 		= '';
		$value 		= '';
		$tokens 	= token_get_all($php);
		$token 		= reset($tokens);
		while ($token) {
		//    dump($state, $token);
		    if (is_array($token)) {
		        if ($token[0] == T_WHITESPACE || $token[0] == T_COMMENT || $token[0] == T_DOC_COMMENT) {
		            // do nothing
		        } else if ($token[0] == T_STRING && strtolower($token[1]) == 'define') {
		            $state = 1;
		        } else if ($state == 2 && $this->is_constant($token[0])) {
		            $key = $token[1];
		            $state = 3;
		        } else if ($state == 4 && $this->is_constant($token[0])) {
		            $value = $token[1];
		            $state = 5;
		        }
		    } else {
		        $symbol = trim($token);
		        if ($symbol == '(' && $state == 1) {
		            $state = 2;
		        } else if ($symbol == ',' && $state == 3) {
		            $state = 4;
		        } else if ($symbol == ')' && $state == 5) {
		            $defines[$this->strip($key)] = $this->strip($value);
		            $state = 0;
		        }
		    }
		    $token = next($tokens);
		}
 
		return $defines;
 
	}
 
	protected function generateDbForm($fields = null, $forceDisplay = false){
 
		if ($fields===null && !$forceDisplay){
			return;
		}
 
		$form = "<form method='post' name='dbForm' class='form-horizontal col-vert-20' role='form'>";
 
		$form.= "<div class='form-group'><label class='col-sm-2&#x20;control-label'>Host</label><div class='col-sm-10'><input name='host' type='text' placeholder='Enter host name' required='required' class='form-control' value='".(isset($fields->host) ? $fields->host : '')."'></div></div>";
 
		$form.= "<div class='form-group'><label class='col-sm-2&#x20;control-label'>Table</label><div class='col-sm-10'><input name='table' type='text' placeholder='Enter table name' required='required' class='form-control' value='".(isset($fields->table) ? $fields->table : '')."'></div></div>";
 
		$form.= "<div class='form-group'><label class='col-sm-2&#x20;control-label'>User</label><div class='col-sm-10'><input name='username' type='text' placeholder='Enter user name' required='required' class='form-control' value='".(isset($fields->username) ? $fields->username : '')."'></div></div>";
 
		$form.= "<div class='form-group'><label class='col-sm-2&#x20;control-label'>Password</label><div class='col-sm-10'><input name='password' type='text' placeholder='Enter password' required='required' class='form-control' value='".(isset($fields->password) ? $fields->password : '')."'></div></div>";
 
		$form.= "<div class='form-group'><div class='col-sm-12'><button type='submit' name='button-submit' class='btn&#x20;btn-success btn-lg pull-right' value=''>
		<span class='glyphicon glyphicon-download'></span>&nbsp;Download</button></div></div>";
 
 
		$form.= "</form>";
 
 
		return $form;
	}
 
	protected function getPlatform($options){
 
		$error          = '<div class="pull-right text-warning"><span class="glyphicon glyphicon-warning-sign status"></span></div>';
		$notFound       = '<div class="pull-right text-danger"><span class="glyphicon glyphicon-remove status"></span></div>';
		$found          = '<div class="pull-right text-success"><span class="glyphicon glyphicon-ok status"></span></div>';
		$out			= '<li class="list-group-item">';
		$logoW			= isset($options->logoW) ? $options->logoW : '213';
		$logoH          = isset($options->logoH) ? $options->logoH : '120';
		$logo 			= "<img src='".(isset($options->logo) ? $options->logo : "holder.js/{$logoW}x{$logoH}")."' height='{$logoH}' width='{$logoW}' alt='platform logo' longdesc='logo representing the platform option' />";
		$dbArgs 		= new StdClass(); 
 
		if (isset($options->conf) && file_exists($options->conf)){
			if (($fp 	= fopen($options->conf, "r"))!==false){
				$params = (object) $this->getDefinitions(stream_get_contents($fp)); 
				foreach(array('host','table','username','password') AS $option){
						$dbArgs->{$option} = isset($options->{$option}) && isset($params->{$options->{$option}}) ? $params->{$options->{$option}} : '';
				}				
	      		$out	.= $found.$logo.$this->generateDbForm($dbArgs, isset($options->force) ? $options->force : null);
	      		fclose($fp);
	      	} else {
	      		$out	.= $error.$logo.$this->generateDbForm(null, isset($options->force) ? $options->force : null);
	      	}
		} else {
			$out		.= $notFound.$logo.$this->generateDbForm(null, isset($options->force) ? $options->force : null);
		}
		$out.= '</li>';
 
		return $out;
 
	}
 
	protected function getPlatforms(){
 
		$out 			= '<ul class="list-group">';
		$out			.= $this->getPlatform((object) array(
			'conf'		=> 'wp-config.php',
			'logo'		=> 'https://s.w.org/about/images/logos/wordpress-logo-32-blue.png',
			'logoW'		=> '32',
			'logoH'		=> '32',
			'host'		=> 'DB_HOST',
	      	'table'		=> 'DB_NAME',
	      	'username'	=> 'DB_USER',
	      	'password' 	=> 'DB_PASSWORD'
			));
 
		$out			.= $this->getPlatform((object) array(
			'conf'		=> 'config/site.php',
			'logo'		=> 'https://www.concrete5.org/files/3613/5517/8150/concrete5_Wordmark_200x37.png',
			'logoW'		=> '200',
			'logoH'		=> '37',
			'host'		=> 'DB_SERVER',
	      	'table'		=> 'DB_DATABASE',
	      	'username'	=> 'DB_USERNAME',
	      	'password' 	=> 'DB_PASSWORD'
			));
 
		/*$out			.= $this->getPlatform((object) array(
			'conf'		=> 'config/autoload/local.php',
			'logo'		=> 'http://clloh.com/wp-content/uploads/2015/08/zf2-logo-128x128.png',
			'logoW'		=> '128',
			'logoH'		=> '128',
			'host'		=> 'DB_SERVER',
	      	'table'		=> 'DB_DATABASE',
	      	'username'	=> 'DB_USERNAME',
	      	'password' 	=> 'DB_PASSWORD'
			));*/
 
		$out			.= $this->getPlatform((object) array(
			'logo'		=> 'https://www.mysql.com/common/logos/logo-mysql-170x115.png',
			'logoW'		=> '170',
			'logoH'		=> '115',
			'force'		=> true,
			));
 
 
		return $out.'</ul>';
	}
 
	protected function getHeader(){
		return '<html><head><title>Restricted area</title><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><script src="https://code.jquery.com/jquery-3.2.1.js" integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=" crossorigin="anonymous"></script><script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/holder/2.9.4/holder.js"></script><META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW"><style>.col-vert-20{margin-top:20px;}.col-vert-100{margin-top:100px;}.status{font-size:30px;}</style></head><body><div class="container-fluid"><div class="row">';
	}
 
	protected function getFooter(){
		$footer = '</div></div>';
 
		if ($this->authentication) {
 
			$footer .= '<div class="modal fade" id="confirmationModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
				  <div class="modal-dialog modal-sm" role="document">
				    <div class="modal-content">
				      <div class="modal-header">
				        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
				        <h4 class="modal-title" id="myModalLabel"><span class="glyphicon glyphicon-lock"></span>&nbsp;Log out request.</h4>
				      </div>
				      <div class="modal-body">
				        Are you sure you wish to logout '.$this->authentication->username.'?
				      </div>
				      <div class="modal-footer">
				        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
				        <a type="button" class="btn btn-primary" href="?logout=true">Confirm</a>
				      </div>
				    </div>
				  </div>
				</div>
				</body></html>';
		}
 
		return $footer;
	}
 
	protected function loginForm($inErrorState = false){
		return '<div class="col-md-6 well well-large col-md-offset-3 col-vert-100"><h3><span class="glyphicon glyphicon-lock"></span> '.($inErrorState ? 'Access Denied' : 'Secure Area' ).'</h3><form method="post" name="login" class="form-horizontal col-vert-20" role="form"><div class="form-group '.($inErrorState ? 'has-error' : '').'"><label class="col-sm-2&#x20;control-label">Username</label><div class=" col-sm-10"><input name="username" type="text" placeholder="Enter&#x20;username" required="required" class="form-control" value="">'.($inErrorState ? '<ul class="help-block"><li>Invalid username &amp; password combination</li></ul>' : '').'</div></div><div class="form-group '.($inErrorState ? 'has-error' : '').'"><label class="col-sm-2&#x20;control-label">Password</label><div class=" col-sm-10"><input name="password" type="password" required="required" placeholder="Password" class="form-control" value="">'.($inErrorState ? '<ul class="help-block"><li>Invalid username &amp; password combination</li></ul>' : '').'</div></div><div class="form-group "><div class=" col-sm-10 col-sm-offset-2"><button type="submit" name="button-submit" class="btn&#x20;btn-default" value="">Login</button></div></div></form></div>';
	}
 
	protected function getDownloadOptions($inErrorState = false){ 
		return '<div class="col-md-6 col-md-offset-3 col-vert-100"><div class="panel panel-primary"><div class="panel-heading"><span class="glyphicon glyphicon-wrench"></span>&nbsp;Export options<button class="pull-right btn btn-danger btn-xs" data-toggle="modal" data-target="#confirmationModal">'.$this->authentication->username.'&nbsp;<span class="glyphicon glyphicon-remove-circle"></span></button></div>'.$this->platforms.'</div></div>'; 
	}
 
	protected function setUsers(array $users = null){
        if ($users==null){
            $users = array();
        }
        foreach($users AS $key=>$user){
        	$users[$key] = (object) $user;
        }
        $this->_users = (object) $users;
        return $this;
    }
 
    protected function getUsers(){
 
        if (!isset($this->_users)){
            $this->setUsers();
        }
        return $this->_users;
    }
 
	protected function setPasswordEncryption($function = null){
        if ($function==null){
            $function = function($val){return $val;};
        }
        $this->_passwordEncryption = $function;
        return $this;
    }
 
    protected function getPasswordEncryption(){
 
        if (!isset($this->_passwordEncryption)){
            $this->setPasswordEncryption();
        }
        return $this->_passwordEncryption;
    }
 
    protected function PasswordEncrypt($pass = ''){
 
    	$encryptor 	= $this->getPasswordEncryption();
    	return call_user_func($encryptor, $pass);
 
    }
 
    protected function generateUserToken(\StdClass $user){
    	return md5((isset($user->username) ? $user->username : uniqid()).self::APP_SALT.(isset($user->password) ? $user->password : uniqid()));
    }
 
    protected function setAuthentication(\StdClass $user){
    	$this->setSessionVar(self::APP_AUTH, $this->generateUserToken($user));
    	return $this;
    }
 
    protected function getAuthentication(){
    	$token 	= $this->getSessionVar(self::APP_AUTH);
    	foreach($this->users AS $validUser){
    		$validToken = $this->generateUserToken($validUser);
    		if ($token==$validToken){
    			return $validUser;
    		}
    	}
 
    }
 
    protected function authenticateUser(\StdClass $user){
 
		foreach($this->users AS $validUser){
 
			if ($user->username==$validUser->username && $this->passwordEncrypt($user->password)==$validUser->password){
				$this->authentication 	= $validUser;
				$this->state 			= 'options';
				return $this->authentication;
			}
		}
 
    }
 
	public static function Init(array $options = array()){
 
		static $inst 	= null;
        if ($inst 		=== null) {
            $inst 		= new dbDump($options);
        }
 
        if (isset($inst->get->logout)){
        	$inst->destroySession();
        	header('Location: '.$_SERVER['PHP_SELF']);
        	die;
        }
 
        if (!$inst->authentication){
        	$inst->state = null;
        }
 
		switch($inst->state){
			case 'options':
 
				//var_dump($inst->authentication);
				if ($inst->isPost()){
 
					$hostname 	= $inst->getPostVar('host');
					$table 		= $inst->getPostVar('table');
					$username 	= $inst->getPostVar('username');
					$password 	= $inst->getPostVar('password');
					$command 	= "mysqldump --add-drop-table --host=$hostname --user=$username --password=$password $table";
 
					header('Content-Description: File Transfer');
					header('Content-Type: application/octet-stream');
					header('Content-Disposition: attachment; filename='.basename($table."_".date("Y-m-d_H-i-s").".sql"));
					system($command);
					exit();
				} else {
					echo $inst->header;					
					echo $inst->downloadOptions;
					echo $inst->footer;
				}
			break;
			default:
 
				if ($inst->isPost()){
					if ($inst->authenticateUser($inst->post)){
						$inst->state = 'options';
						header("Refresh:0");
						die;
					} else {
						echo $inst->header;
						echo $inst->loginForm(true);
						echo $inst->footer;
					}
 
				} else {
					echo $inst->header;
					echo $inst->loginForm();
					echo $inst->footer;
				}
			break;
		}
 
	}
 
    public function __set($name, $value)
    {
        $method = 'set' . $name;
        if (method_exists($this, $method)) {
            $this->$method($value);
            return $this;
        }
 
        throw new \Exception('"'.$name.'" is an invalid property of '.__CLASS__.' assignment failed!');
 
    }
 
    public function __get($name)
    {
 
        $method = 'get' . $name;
        if (method_exists($this, $method)) {
            return $this->$method();
        }
 
        throw new \Exception('Invalid '.__CLASS__.' property '.$name);
    }
 
    public function setOptions(array $options)
    {
        $methods = get_class_methods($this);
        foreach ($options as $key => $value) {
            $method = 'set' . ucfirst($key);
            if (in_array($method, $methods)) {
                $this->$method($value);
            }
        }
        return $this;
    }  
 
    private function __construct(array $options = null)
    {     
    	// env
    	set_time_limit(20);
 
        if (is_array($options)) {
            $this->setOptions($options);
        }
 
    }
 
	private function __clone(){}
}
VN:F [1.9.9_1125]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.9_1125]
Rating: 0 (from 0 votes)
826 views

Zend framework 2 DomPdf No block-level parent found. Not good. error message

July 25th, 2016

This error can be caused by many things, but the most notable is when attempting to reuse DomPdf to render more than one PDF.

This is to do with the way the service manager passes a single instance, and DOMPDF does not clean up after itself properly.

Attempting code like:

$html   = $this->getServiceLocator()->get('viewpdfrenderer')->getHtmlRenderer()->render($pdf);
$eng    = $this->getServiceLocator()->get('viewpdfrenderer')->getEngine();
 
$eng->load_html($html);
$eng->render();

Will fail, however despite the answer being very hard to find online the solution is rather simple, simply use the html renderer but request dompdf from the service manager, below I will render multiple PDF’s with different views, save them as files ready to be attached to an email.

 
        // first PDF
        $pdf = new PdfModel();
        $pdf->setTerminal(true);
        $pdf->setTemplate('template1');
        $pdf->setVariables(array(
          'foo'         => 'bar'
        ));
 
        $html                   = $this->getServiceLocator()->get('viewpdfrenderer')->getHtmlRenderer()->render($pdf);
        $dompdf                 = $this->getServiceLocator()->get('dompdf'); // get fresh instance everytime
 
        $dompdf->load_html($html);
        $dompdf->render();
        file_put_contents('file1.pdf', $dompdf->output());
 
 
 
 
        // second pdf
        $pdf = new PdfModel();
        $pdf->setTerminal(true);
        $pdf->setTemplate('template2');
        $pdf->setVariables(array(
          'foo'         => 'bar'
        ));
 
        $html                   = $this->getServiceLocator()->get('viewpdfrenderer')->getHtmlRenderer()->render($pdf);
        $dompdf                 = $this->getServiceLocator()->get('dompdf'); // get fresh instance everytime
 
        $dompdf->load_html($html);
        $dompdf->render();
        file_put_contents('file2.pdf', $dompdf->output());

Happy coding!

VN:F [1.9.9_1125]
Rating: 10.0/10 (2 votes cast)
VN:F [1.9.9_1125]
Rating: 0 (from 0 votes)
2,945 views

ZF2 different layouts in modules

June 4th, 2013

To enable a different layout in a module, to your module.php for the module define a new layout like so

public function init(ModuleManager $mm)
    {
        $mm->getEventManager()->getSharedManager()->attach(__NAMESPACE__, 'dispatch', function($e) {
            $e->getTarget()->layout('admin/layout');
        });
    }

then within your module.config.php view_manager settings define the template

'view_manager' => array(
        'template_map' => array(
            'admin/layout'           => __DIR__ . '/../view/layout/cms.phtml',
        ),
        'template_path_stack' => array(
            __DIR__ . '/../view',
        ),
    ),

or you can define a direct path in your module.php without any template mapping i.e

public function init(ModuleManager $mm)
    {
        $mm->getEventManager()->getSharedManager()->attach(__NAMESPACE__, 'dispatch', function($e) {
            $e->getTarget()->layout('layout/admin');
        });
    }

This will load module/view/layout/admin.phtml when this module is run

VN:F [1.9.9_1125]
Rating: 6.1/10 (8 votes cast)
VN:F [1.9.9_1125]
Rating: +2 (from 4 votes)
16,433 views

adding password authentication for a zend cms or controller

December 13th, 2011

This is a very quick way to add password protection to a controller such as a cms controller.

This code intercepts the login within the init() method of your chosen controller, if they are logged in they are free to go, if not they are required to login, the form is rendered and validated against the access model.

The session is obfuscated to deter tampering.

so firstly in your controller init() add

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$adminSession = new Zend_Session_Namespace('Admin');
$this->access = new Application_Model_accessControl(); // access control
 
// logged in user
$loginMsg = 'Please login';
$loginForm = new Zend_Form;
$loginForm
	->setMethod('post')
	->setAttrib('id','login')
	->addElement('text','user',array('label'=>'Username','required'=>true))
	->addElement('password','pass',array('label'=>'Password','required'=>true))
	->addElement('submit','Login');
 
if ($this->getRequest()->isPost() && $loginForm->isValid($_POST)){
	$session = $this->access->validateUser(
		$loginForm->getValue('user'), 
		$loginForm->getValue('pass')
		);
 
	if ($session){
		$adminSession->loggedInSession = $session;
		$adminSession->loggedInUser = $loginForm->getValue('user');
	}
 
	$loginMsg='Access denied';
} 			
 
if (!$this->access->sessionIsValid($adminSession->loggedInSession) || !$adminSession->loggedInUser){
       	$this->view->header=$loginMsg;			
	$this->view->content = $loginForm;
	$this->render('login');  
} else {
	// renew session, will always be the "Now" session, but three are provided, see the model 
	$adminSession->loggedInSession = $this->access->getValidSession();
    	$this->view->userIdent = $adminSession->loggedInUser;
}

$this->view->userIdent will always contain the logged in user

The next step is to create the model for authentication in models/accessControl.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<?php
 
class Application_Model_accessControl
{
 
 
	public function __construct(){
 
		// set users, password is the key, because this is less likely to be duplicated
        $this->setUsers(
        	array(
				'password1'=>'admin',
				'password2'=>'admin'
				)
       		);
        // salt for session key
		$this->setSalt('MySaltGoesHere1234');
	}
 
	public function validateUser($username, $password){
 
		/*
		 * return session if correct, null otherwise
		 */
 
		$users = $this->getUsers();
 
		if (isset($users[$password]) && $users[$password]==$username){
			return $this->getValidSession();
		}
	}
	public function sessionIsValid($session,$debug=false){
 
		$validSessions = $this->getValidSessions();
		if ($debug){
			echo "MY KEY: $session<br >KEYS: ".print_r($validSessions,true);
		}
		return in_array($session, $validSessions) ? true : false;
	}
 
	public function getValidSessions(){
 
		$sessions = array(
			$this->getValidSession('past'),
			$this->getValidSession('now'),
			$this->getValidSession('future')
			);
 
		return $sessions;
	}
	public function getValidSession($for='now'){
 
		/*
		 * Three sessions are provided,
		 * 
		 * past, now and present
		 * 
		 * past, person logs in at 11:59 spends ten minutes editing, clicks save at 12:09, past would be the valid session
		 * now, person is logged in during 11:00 - 11:59
		 * future, is provided encase of time travel, or if the british summer time kicks in while editing, unlikely but more is better than not enough...
		 */
 
		$hour = intval(date('H'));
 
		switch($for){
			case 'past' : 
				$validSession = ($hour-1) < 0 ? 23 : $hour-1;
			break;
			case 'now' : default:
				$validSession = $hour;
			break;
			case 'future' : 
				$validSession = ($hour+1) > 23 ? 0 : $hour+1;
			break;
 
		}
 
		/*
		 * obsfucation
		 */
		// firstly grab specific details to stop session hijacking 
		$ip = $_SERVER['REMOTE_ADDR'];
		$browser = $_SERVER['HTTP_USER_AGENT'];
		// then mix it up and md5 it
		$validSession = $ip.$validSession.$this->getSalt().$browser;
 
		if (!getenv('APPLICATION_ENV')){
			$validSession = md5($validSession);
		}
 
		return $validSession;
	}
 
	public function setUsers($users){
		$this->users = $users;
	}
	public function getUsers(){
		return $this->users;
	}
	public function setSalt($salt){
		$this->salt = $salt;
	}
	public function getSalt(){
		return $this->salt;
	}
 
 
}

and finally create a view login.phtml (this is just bare bones)

1
2
<?php echo "<h2>{$this->header}</h2>";  ?>
<?php echo $this->content;  ?>

Thats it!

VN:F [1.9.9_1125]
Rating: 8.3/10 (3 votes cast)
VN:F [1.9.9_1125]
Rating: 0 (from 0 votes)
8,569 views

session_start hangs when it used to work

December 13th, 2011

I had a problem with my zend application hanging with a white screen for no reason.
I narrowed it down to when

1
$adminSession = new Zend_Session_Namespace('Admin');

was executed, this is just a session? so debugging further, confirmed that session_start() hangs when it used to work.

There are lots of explanations for this, but before you start modifying ini settings, just try this

1
2
3
session_write_close();
session_start();
die(print_r($_SESSION,true));

I found this resolved the problem completely.
I then just removed this debug-code and went back to developing my zend app.

VN:F [1.9.9_1125]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.9_1125]
Rating: +1 (from 1 vote)
3,718 views

ckeditor to upload images

September 19th, 2011

A few posts on how to do this, and a lot of frustrated people so here is how:

Download both ckeditor and ckfinder.

Decompress them into the root directory.

Include them in your php

include_once ‘ckeditor/ckeditor.php’;
include_once ‘ckfinder/ckfinder.php’;

hopefully no error messages? ok cool…. now simply

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
 
$ckeditor = new CKEditor();
$ckeditor->basePath = '/ckeditor/';
$ckeditor->config['filebrowserBrowseUrl'] = '/ckfinder/ckfinder.html';
$ckeditor->config['filebrowserImageBrowseUrl'] = '/ckfinder/ckfinder.html?type=Images';
$ckeditor->config['filebrowserFlashBrowseUrl'] = '/ckfinder/ckfinder.html?type=Flash';
$ckeditor->config['filebrowserUploadUrl'] = '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files';
$ckeditor->config['filebrowserImageUploadUrl'] = '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Images';
$ckeditor->config['filebrowserFlashUploadUrl'] = '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Flash';
$ckeditor->editor('CKEditor1');
 
?>

To add the field to the form.

Ensure that in ckfinder/userfiles is writable

You also need to alter in ckfinder/userfiles/config.php the function CheckAuthentication(), to return true, take note of the warning!!

ive put it all together in one zip file displaying the submission here

VN:F [1.9.9_1125]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.9_1125]
Rating: 0 (from 0 votes)
4,124 views

database class php

August 8th, 2011

Updated the database class

Usage:

1
2
3
4
5
6
 
// min instantiation
$dataBase = new DB('hostname','username','password','database');
 
// max instantiation
$dataBase = new DB('hostname','username','password','database',DEBUG_LEVEL,array('admin@domain.com','admin@domain2.com));

Class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
 
class DB{
 
	/* 
	 * DESCRIPTION:		Object class, Handles all database requests and returns content accordingly
	 * WRITER:			Adrian Callaghan 12,08,08      
	 * UPDATED: 		Adrian Callaghan 08,08,11
	 * 
	 * 
	 * errLvl 
	 * 		(0), none, 
	 * 		(1) show a user error, 
	 * 		(2) (1) + mysql error
	 * 		(3) (2) + show a full error (mysql errors), 
	 * 		(4) (3) + plus debugging 
	*/
 
 
	private $host, $usr, $pwd, $errLvl, $mySqlHost, $dataBase, $emailAddresses;
 
 
	public function __construct($host, $usr, $pwd, $db, $errLvl=0, $adminEmails=array()) {
 
		/*
		 * Sets up a new connection
		 */
 
		// MIN required
		$this->setHost($host);
		$this->setUsr($usr);
		$this->setPwd($pwd);
 
		$this->setErrLvl($errLvl); // sets defualt RTE
		$this->setEmailErrsTo($adminEmails);
 
		// connect
		$this->connect();
		$this->setDb($db);
 
		}
 	public function __destruct(){
 		/*
 		 * Close the connection
 		 */
 		$this->disconnect();
 	}
	protected function setHost($host='localhost'){
		/*
		 * Sets the hostname
		 */
		$this->host = $host;
	}	
 	protected function setUsr($usr=''){
		/*
		 * Sets the username
		 */
 		$this->usr = $usr;
	}	
	protected function setPwd($pwd=''){
		/*
		 * Sets the password
		 */
		$this->pwd = $pwd;
	}	
	protected function setErrLvl($errLvl=0){
		/*
		 * Sets the error reporting level
		 */
		$this->errLvl = $errLvl;
	}	
	protected function connect(){
		/*
		 * Connect to server
		 */
		$this->mySqlHost = @mysql_connect($this->host, $this->usr, $this->pwd);
		if (!$this->mySqlHost) {
			$this->error('Cannot connect to server',mysql_error());
		}	
 
	}
	protected function disconnect() {
		/*
		 * closes current connection
		 */ 
		@mysql_close($this->mySqlHost);
	}
	public function setDb($db){
		/*
		 * Set the database
		 */
		$this->dataBase = @mysql_select_db($db,$this->mySqlHost);
		if (!$this->dataBase) {
			$this->error('Cannot select database',mysql_error());
		}
	}
	public function setEmailErrsTo($email = array()){
 
		// ensure it is an array
		$email = !is_array($email) ? array($email) : $email;
 
		// if empty return
		if (empty($email)){
			return;
		}
 
		// assign the email addresses
		$this->emailAddresses = $email;
	}
 
 
 
 
	function getQuery($SQL){
		// executes a query
		$result = @mysql_query($SQL);
		if (!$result) {
			$this->error('Invalid query',mysql_error(),$SQL);
			}
		// create a 2D array of results
		$return = array();
		while ($row = mysql_fetch_assoc($result)) $return[] = $row;
		return $return;
		}
 
 
 
 
	function setQuery($SQL){
		// executes a query without returning any results, used for insert, create etc, returns the ID of the last auto-increment
		$result = @mysql_query($SQL);
		if (!$result) {
			$this->error('Invalid query',mysql_error(),$SQL);
			}
		$return = mysql_insert_id();
		return $return;
		}
 
 
 
 
	public function error($message, $mysqlErr='', $SQL=''){
 
		/*
		 * Handles errors
		 * 
		 */
 
		switch ($this->errLvl){
 
			case 0: break;
			case 1:	$mysqlErr=''; // kill the mysql output
			case 2:	$SQL=''; // kill the sql output
			case 3: 
			case 4: 
				echo "<h1 style='color:#444444;'>$message</h1><hr>";
				if ($mysqlErr!=='') {
					echo "<p><span style='color:#ff0000; font-weight:bold;'>Mysql: </span>$mysqlErr</p>";
				}
				if ($SQL!=='') {
					echo "<p><span style='color:#ff0000; font-weight:bold;'>Whole query: </span>$SQL</p>";
				}			
 
		}
 
 		$email = $this->generateEmail(array('Error'=>$message,'Mysql'=>$mysqlErr,'Sql'=>$SQL,'Err Level'=>$this->errLvl));
 
 		// three is for debugging
 		if ($this->errLvl>3){
			echo $email;
		}
 
		if (!empty($this->emailAddresses)){
 
			$sent = $this->sendEmails($email);
 
 			if ($sent) echo '<h2>The administrator has been notified</h2>';
			else {
				echo '<h2>Please notify the administrator';
				echo count($this->emailAddresses)>1 ? "'s " : " ";
				echo implode(' or ',$this->emailAddresses);
				echo '</h2>';
			}
 
		}
 
		exit();
	}	
	private function generateEmail($err=array()){
 
		$fields = array(
			'Server name'=>$_SERVER['SERVER_NAME'],
			'Query'=>$_SERVER['SCRIPT_FILENAME'].'?'.$_SERVER['QUERY_STRING'],
			'Ip'=>$_SERVER['REMOTE_ADDR'].':'.$_SERVER['REMOTE_PORT'],
			'@'=>date("D dS M,Y h:i a")
		);	
 
		$rtn = '<table bgcolor="#cccccc">';
		foreach (array_merge($fields, $err) AS $title=>$value){
			$rtn.="<tr><td bgcolor='#aaaaaa'>$title</td><td bgcolor='#bbbbbb'>$value</td></tr>";
		}
		return $rtn.'</table>';
 
	}
	public function sendEmails($reciptents=array()){
 
		// email message
		$Name = $_SERVER['SERVER_NAME']; //senders name 
		$email = "noreply@".$_SERVER['SERVER_NAME']; //senders e-mail adress 
 
		$subject = $_SERVER['SERVER_NAME']." Error"; //subject 
 
		$header = 'MIME-Version: 1.0' . "\r\n";
		$header.= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";		
		$header.= "From: ". $Name . " <" . $email . ">\r\n"; 
 
		$success=false;
		foreach ($this->emailAddresses AS $admin_email){
			$sent = @mail($admin_email, $subject, $mail_body, $header);
			if ($sent) $success=true; // holds state for any email being succesfully sent
		}
		return $success;
	}
}
VN:F [1.9.9_1125]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.9_1125]
Rating: 0 (from 0 votes)
6,000 views