Fizz Buzz and Fibbonacci combined
May 11th, 2017I 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,"; |
WordPress, concrete5, ZF2, PHP, mysql database dump
March 22nd, 2017Here 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:
When nothing is detected it will still offer the manual entering of the username and password.
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.
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 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 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 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 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 btn-success btn-lg pull-right' value=''> <span class='glyphicon glyphicon-download'></span> 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">×</span></button> <h4 class="modal-title" id="myModalLabel"><span class="glyphicon glyphicon-lock"></span> 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 control-label">Username</label><div class=" col-sm-10"><input name="username" type="text" placeholder="Enter username" required="required" class="form-control" value="">'.($inErrorState ? '<ul class="help-block"><li>Invalid username & password combination</li></ul>' : '').'</div></div><div class="form-group '.($inErrorState ? 'has-error' : '').'"><label class="col-sm-2 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 & 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 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> Export options<button class="pull-right btn btn-danger btn-xs" data-toggle="modal" data-target="#confirmationModal">'.$this->authentication->username.' <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(){} } |
Zend framework 2 DomPdf No block-level parent found. Not good. error message
July 25th, 2016This 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!
2,953 viewsZF2 different layouts in modules
June 4th, 2013To 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
16,435 viewsadding password authentication for a zend cms or controller
December 13th, 2011This 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!
8,572 viewssession_start hangs when it used to work
December 13th, 2011I 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.
ckeditor to upload images
September 19th, 2011A 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
4,131 viewsdatabase class php
August 8th, 2011Updated 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; } } |