I'm currently a beginner developer and have just started my first big project whilst I have spare time, What I'm trying to do is basically write variables to a html/tpl document, Which I have currently got working, Here is my code:
private function index(){
$username = 'MyUsername';
$onlineTime = 'MyOnlineTime';
$this->setParams('Username', $username); // $username Will be replaced by database queried results once completed.
}
And here is the setParams function.
function setParams($item1, $item2){
ob_start();
$theme = 'default';
include_once T . '/'.$theme.'/index.php'; // T . is defined at the beginning of the document.
if ((($html = ob_get_clean()) !== false) && (ob_start() === true))
{
echo preg_replace('~{(['.$item1.']*)}~i', ''.$item2.'', $html, 1);
}
}
And here is the coding inside the html/tpl document.
{username} has been online for {onlineTime} Hours
This is probably a very simple code for some of you but as this is my first attempt this is all I can do.
What I would like to do is have it so you can setParams as many times as you want without changing the $variable names like so:
private function index(){
$username = 'MyUsername';
$onlineTime = 'MyOnlineTime';
$this->setParams('Username',$username);
$this->setParams('OnlineTime', $onlineTime);
}
whilst keeping the setParams($item1, $item2)
But as you can imagine this just cuts the code completely. Does anyone know a solution to this problem? I've been searching all day without any real luck.
Thanks In Advance,
Ralph
I think what you need is a class with a static method;
<?php
class Params {
public static $params = array();
public static function setParam($key, $value) {
self::$params[$key] = $value;
}
public static function getParam($key) {
if (isset(self::$params[$key])) {
return self::$params[$key];
}
}
}
// Usage
// Set Username
Params::setParam("username", "JohnDoe");
Params::setParam("password", "12345");
echo Params::getParam("username");
echo Params::getParam("password");
Related
Until yesterday I was burning my brain trying to switch from a procedural thinking to a OOP thinking; this morning I gave up. I said to my self I wasn't probably ready yet to understand it.
I started then coding in the usual way, writing a function to check if there's the cookie "logged" or not
function chkCookieLogin() {
if(isset($_COOKIE["logged"])) {
$logged = 'true';
$cookieValue = $_COOKIE["logged"];
return $logged;
return $cookieValue;
}
else {
$logged = 'false';
return $logged;
}
}
$result = chkCookieLogin();
if($result == 'true'){
echo $cookieValue;
}
else {
echo 'NO COOKIE';
}
since I run across a problem: I wanted to return two variables ($logged and $cookieValue) instead of just one. I google it and I found this answer where Jasper explains a method using an OOP point of view (or this is what I can see).
That answer opened me a new vision on the OOP so I tried to rewrite what I was trying to achieve this way:
class chkCookie {
public $logged;
public $cookieValue;
public function __construct($logged, $cookieValue) {
$this->logged = $logged;
$this->cookieValue = $cookieValue;
}
function chkCookieLogin() {
$out = new chkCookie();
if(isset($_COOKIE["logged"])) {
$out->logged = 'true';
$out->cookieValue = $_COOKIE["logged"];
return $out;
}
else {
$out->logged = 'false';
return $out;
}
}
}
$vars = chkCookieLogin();
$logged = $vars->logged;
$cookieValue = $vars->cookieValue;
echo $logged; echo $cookieValue;
Obviously it didn't work at the first attempt...and neither at the second and the third. But for the first time I feel I'm at one step to "really touch" the OOP (or this is what I think!).
My questions are:
is this attempt correctly written from the OOP point of view?
If yes, what are the problems? ('cause I guess there's more than one)
Thank you so much!
Credit to #NiettheDarkAbsol for the idea of returning an Array data-type.
Using dependency injection, you can set-up an object like this:
class Factory {
private $Data = [];
public function set($index, $data) {
$this->Data[$index] = $data;
}
public function get($index) {
return $this->Data[$index];
}
}
Then to use the DI module, you can set methods like so (using anonymous functions):
$f = new Factory();
$f->set('Cookies', $_SESSION);
$f->set('Check-Cookie', function() use ($f) {
return $f->get('Cookies')['logged'] ? [true, $f->get('Cookies')['logged']] : [false, null];
});
Using error checks, we can then call the method when and as we need it:
$cookieArr = is_callable($f->get('Check-Cookie')) ? call_user_func($f->get('Check-Cookie')) : [];
echo $cookieArr[0] ? $cookieArr[1] : 'Logged is not set';
I'd also consider adding constants to your DI class, allowing more dynamic approaches rather than doing error checks each time. IE, on set() include a constant like Factory::FUNC_ARRAY so your get() method can return the closure already executed.
You can look into using ternary operators if you're confused.
See it working over at 3v4l.org.
If it means anything, here is an OOP styled approach.
I'm trying to learn about Object Oriented Programming and I want to turn this code into such. I've got some knowledge so far from google and here and in particular http://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762.
The way I understand it is I need classes that contain a certain set of instructions that can be used with universal objects outside of those classes.
My idea so far has been to set up a User class where names are stored (coming from a HTML/PHP form).
class User {
public $nameStore, $fName, $lName, $email;
public function __construct ($fName, $lName, $email) {
$this->$fN = $fName;
$this->$lN = $lName;
$this->$eN = $email;
}
Like the above^. But I'm still confused about where other instructions of my code should go. That's where I need the most help. From what I've read, it hasn't helped me get the full grasp of what I need to do. If someone could help get me started in the right direction on how to make my code into an OOP type I would greatly appreciate it. Thanks!
Below is my procedural code that I want to convert to OOP.
<?php
session_start();
$formNames = $_POST['names'];
$active = (isset($_POST['activate'])) ? $_POST['activate'] : false;
//checks if activate checkbox is being used
$email = '#grantle.com';
$fullnames = explode(", ", $_POST['names']);
if ($active == true) {
$active = '1';
//sets activate checkbox to '1' if it has been selected
}
/*----------------------Function to Insert User-------------------------*/
function newUser($firstName,$lastName,$emailUser,$active,$conn){
//a function to insert a user into a database is here
}
//newUser function enters names in database
/*-------------------------End Function to Insert User--------------------*/
/*-----------------------Function for Errors------------------------------*/
function errorCheck($formNames, $nameSplit, $fullname){
$isValid = false;
if (empty($fullname)) {
$_SESSION['error'][] = '<br><br> Error: Name Missing Here: '.$fullname.'<br><br>';
} elseif (empty($nameSplit[0])) {
$_SESSION['error'][] = '<br><br> Error: First Name Missing Here: '.$fullname.'<br><br>';
} elseif (empty($nameSplit[1])) {
$_SESSION['error'][] = '<br><br> Error: Last Name Missing Here: '.$fullname.'<br><br>';
} elseif (preg_match('/[^A-Za-z, ]/', $fullname)) {
$_SESSION['error'][] = '<br><br> Error: Illegal Character Found in: '.$fullname.'<br><br>';
} else {
$isValid = true;
}
return $isValid;
}
//errorCheck function tests for errors in names and stops them from being entered in the
//database if there are errors in the name. Allows good names to go through
/*-----------------------------End Function for Errors---------------------*/
/*--------------------------Function for Redirect--------------------------*/
function redirect($url){
$string = '<script type="text/javascript">';
$string .= 'window.location = "' .$url. '"';
$string .= '</script>';
echo $string;
}
//redirect function uses a javascript script to redirect user because headers have already been sent.
/*-----------------------------End Function for Redirect-----------------------*/
// Connect to database
I connect to the database here//
// Initialize empty error array
$_SESSION['error'] = array();
foreach ($fullnames as $fullname) {
$nameSplit = explode(" ", $fullname);
//I open the database here
//opens the database
if (errorCheck($formNames, $nameSplit, $fullname)) {
$firstName = $nameSplit[0];//sets first part of name to first name
$lastName = $nameSplit[1];//sets second part of name to last name
$emailUser = $nameSplit[0].$email;//sets first part and adds email extension
newUser($firstName,$lastName,$emailUser,$active,$conn);//do this BELOW only for names that have no errors
}//ends if of errorCheck
}//ends fullnames foreach
if (count($_SESSION['error']) == 0) {
redirect('viewAll.php');
} else {
redirect('form.php');
}
/*Redirects to viewAll page only once and as long as no errors have been found*/
Your
class User {
public $nameStore, $fName, $lName, $email;
public function __construct ($fName, $lName, $email) {
$this->$fN = $fName;
$this->$lN = $lName;
$this->$eN = $email;
}
I would break this up into more specific parts such as GET and SET for each value you are trying to store in the Class:
class User {
private $fName, $lName, $email;
public function set_firstname($fname){
$this->fName = $fname;
}
public function set_surname($lName){
$this->lName = $lName;
}
public function set_email($email){
$this->email = $email;
}
public function get_email(){
return $this->email;
}
public function get_fname(){
return $this->fName;
}
public function get_surname(){
return $this->lName;
}
Then when you create the class, you can add and return each value individually, rather than forcing yourself to do them all at once. This is more flexible. But you can also add the values at the creation of the class as well if you wish, using the __construct similar to what you had already:
public function __construct ($fName = null, $lName = null, $email = null) {
if(!empty($fName)){
$this->set_firstname($fName);
}
if(!empty($lName)){
$this->set_surname($lName);
}
if(filter_var($email, FILTER_VALIDATE_EMAIL) !== false){
$this->set_email($email);
}
}
What this does is for each non-empty value it runs the corresponding SET method. Also checking that the email value is valid before saving it. If no values are passed to the class then it doesn't save anything.
Your setting up of the class is incorrect, firstly you need to include the class file into the working PHP so at the top of your page add:
include "path/to/users.class.php";
And then initiate the class correctly:
$userClassInstance = new User($firstName,$lastName,$emailUser);
When the above line runs, you will then have a User object containing three variables referenced as $userClassInstance. you can do var_dump($userClassInstance);
Be careful as your code has newUser as one line and also has an incorrect number of variables in the construct statement. Generally all the functions in a page should be placed inside an appropriate class, so all your string management functions such as errorCheck() could be put into the Users class to check the values given before assigning them to the variables in the class.
Finally, to view the stored variables you would then do:
print $userClassInstance->get_fname(); //will outout the value of the class $fName
I have created my own little PHP framework for fun, however, I am having trouble passing variables from bootstrap to the views....
if I put an echo,print_r,var_dump my target variable in the bootstrap, the output is displayed in the browser before the tag... yet the target var in bootstrap.php is not available in the view, it is coming up as "" even though at the top of the page it is being output correctly....
Somethings I noticed from similar questions:
- The target variable is not being over written
- The include target path is correct and the file exists
- The file is only being included one time (include_once is only fired once)
Any ideas are greatly appreciated, I am pulling my hair out over here lol...
Source Code
https://gist.github.com/jeffreyroberts/f330ad4a164adda221aa
If you just want to display your site name, I think you can use a constant like that :
define('SITE_NAME', "Jeff's Site");
And then display it in your index.tpl :
<?php echo SITE_NAME; ?>
Or, you can send your variables to the view by extending a little bit your JLR_Core_Views :
class JLR_Core_Views
{
private $data;
public function loadView($templatePath, $data = array())
{
$this->data = $data;
$templatePath = JLR_ROOT . '/webroot/' . $templateName . '.tpl';
if(file_exists($templatePath)) {
// Yes, I know about the vuln here, this is just an example;
ob_start();
include_once $templatePath;
return ob_get_clean();
}
}
function __get($name)
{
return (isset($this->data[$name]))
? $this->data[$name]
: null;
}
}
Then, you can call your template like that :
$view = new JLR_Core_Views();
$view->loadView("index", array("sitename" => "Jeff's Site"));
And here is your index.tpl :
<?php echo $this->siteName; ?>
Below is another example of what you can do.
First, you create this class in order to store all the variables you want :
<?php
class JLR_Repository {
private static $data = array();
public function set($name, $value) {
self::$data[$name] = $value;
}
public function get($name) {
return (isset(self::$data[$name]))
? self::$data[$name]
: null;
}
}
?>
Then, when you want to store something in it :
JLR_Repository::set("sitename", "Jeff's Site");
And in your index.tpl :
<?php echo JLR_Repository::get("sitename"); ?>
try using the 'global' keyword - http://php.net/manual/en/language.variables.scope.php
I searched forever trying to find an answer, but was ultimately stumped. I've been writing code to allow multiple bots to connect to a chat box. I wrote all the main code and checked it over to make sure it was all okay. Then when I got to calling the function needed to make it work, it gave me an error saying:
Notice: Undefined variable: ip in C:\wamp\www\BotRaid.php on line 40
And also an error saying:
Fatal Error: Cannot access empty property in C:\wamp\www\BotRaid.php
on line 40
( Also a screenshot here: http://prntscr.com/ckz55 )
<?php
date_default_timezone_set("UCT");
declare(ticks=1);
set_time_limit(0);
class BotRaid
{
public $ip="174.36.242.26";
public $port=10038;
public $soc = null;
public $packet = array();
##############################
# You can edit below this #
##############################
public $roomid="155470742";
public $userid = "606657406";
public $k = "2485599605";
public $name="";
public $avatar=;
public $homepage="";
##############################
# Stop editing #
##############################
public function retry()
{
$this->connect($this->$ip,$this->$port); //Line 40, where I'm getting the error now.
$this->join($this->$roomid);
while($this->read()!="DIED");
}
public function connect($ip, $port)
{
if($this->$soc!=null) socket_close($this->$soc);
$soc = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
if(!$this->$soc)$this->port();
if(!socket_connect($this->$soc,$this->$ip,$this->$port))$this->port();
}
public function port()
{
$this->$port++;
if($this->$port>10038) $this->$port=10038;
$this->retry();
}
public function join($roomid)
{
$this->send('<y m="1" />');
$this->read();
$this->send('<j2 q="1" y="'.$this->$packet['y']['i'].'" k="'.$this->$k.'" k3="0" z="12" p="0" c"'.$roomid.'" f="0" u="'.$this->$userid.'" d0="0" n="'.$this->$name.'" a="'.$this->$avatar.'" h="'.$this->$homepage.'" v="0" />');
$this->port();
$this->$roomid;
}
public function send($msg)
{
echo "\n Successfully connected.";
socket_write($this->$soc, $this->$msg."\0", strlen($this->$msg)+1);
}
public function read($parse=true)
{
$res = rtrim(socket_read($this->$soc, 4096));
echo "\nSuccessfully connected.";
if(strpos(strtolower($res), "Failed"))$this->port();
if(!$res) return "DIED";
$this->lastPacket = $res;
if($res{strlen($res)-1}!='>') {$res.=$this->read(false);}
if($parse)$this->parse($res);
return $res;
}
public function parse($packer)
{
$packet=str_replace('+','#più#',str_replace(' ="',' #=#"',$packet));
if(substr_count($packet,'>')>1) $packet = explode('/>',$packet);
foreach((Array)$packet as $p) {
$p = trim($p);
if(strlen($p)<5) return;
$type = trim(strtolower(substr($p,1,strpos($p.' ',' '))));
$p = trim(str_replace("<$type",'',str_replace('/>','',$p)));
parse_str(str_replace('"','',str_replace('" ','&',str_replace('="','=',str_replace('&','__38',$p)))),$this->packet[$type]);
foreach($this->packet[$type] as $k=>$v) {
$this->packet[$type][$k] = str_replace('#più#','+',str_replace('#=#','=',str_replace('__38','&',$v)));
}
}
}
}
$bot = new BotRaid; //This is where I had the error originally
$bot->retry();
?>
Line 40 is below the "Stop Editing" line. Anyone have any suggestions? Or perhaps need me to clear some things up?
You are accessing the properties of the class incorrectly.
The line:
$this->connect($this->$ip,$this->$port);
Should be:
$this->connect($this->ip, $this->port);
Since there was no local variable called $ip, your expression was evaluating to $this-> when trying to access the property since PHP lets you access properties and functions using variables.
For example, this would work:
$ip = 'ip';
$theIp = $this->$ip; // evaluates to $this->ip
// or a function call
$method = 'someFunction';
$value = $this->$method(); // evaluates to $this->someFunction();
You will have to change all the occurrences of $this->$foo with $this->foo since you used that notation throughout the class.
As noted in the comment by #Aatch, see the docs on variable variables for further explanation. But that is what you were running into accidentally.
So I'm setting up a system that has a lot of emails, and variable replacement within it, so I'm writing a class to manage some variable replacement for templates stored in the database.
Here's a brief example:
// template is stored in db, so that's how this would get loaded in
$template = "Hello, %customer_name%, thank you for contacting %website_name%";
// The array of replacements is built manually and passed to the class
// with actual values being called from db
$replacements = array('%customer_name%'=>'Bob', '%website_name%'=>'Acme');
$rendered = str_replace(array_keys($replacements), $replacements, $template);
Now, that works well and good for single var replacements, basic stuff. However, there are some places where there should be a for loop, and I'm lost how to implement it.
The idea is there'd be a template like this:
"hello, %customer_name%, thank you for
requesting information on {products}"
Where, {products} would be an array passed to the template, which the is looped over for products requested, with a format like:
Our product %product_name% has a cost
of %product_price%. Learn more at
%product_url%.
So an example rendered version of this would be:
"hello, bob, thank you for requesting
information on:
Our product WidgetA has a cost of $1.
Learn more at example/A
Our product WidgetB has a cost of $2.
Learn more at example/B
Our product WidgetC has a cost of $3.
Learn more at example/C.
What's the best way to accomplish this?
Well, I really dont see the point in a template engine that uses repalcements/regex
PHP Is already a template engine, when you write <?php echo $var?> its just like doing <{$var}> or {$var}
Think of it this way, PHP Already translates <?php echo '<b>hello</b>'?> into <b>hello</b> by its engine, so why make it do everything 2 times over.
The way i would implement a template engine is like so
Firstly create a template class
class Template
{
var $vars = array();
function __set($key,$val)
{
$this->vars[$key] = $val;
}
function __get($key)
{
return isset($this->vars[$key]) ? $this->vars[$key] : false;
}
function output($tpl = false)
{
if($tpl === false)
{
die('No template file selected in Template::output(...)');
}
if(!file_exists(($dir = 'templates/' . $tpl . '.php')))
{
die(sprintf('Tpl file does not exists (%s)',$dir));
}
new TemplateLoader($dir,$this->vars);
return true;
}
}
This is what you use in your login such as index.php, you will set data just like an stdClass just google it if your unsure. and when you run the output command it sends the data and tpl to the next class below.
And then create a standalone class to compile the tpl file within.
class TemplateLoader
{
private $vars = array();
private $_vars = array(); //hold vars set within the tpl file
function __construct($file,$variables)
{
$this->vars = $variables;
//Start the capture;
ob_start();
include $file;
$contents = ob_get_contents();
ob_end_clean(); //Clean it
//Return here if you wish
echo $contents;
}
function __get($key)
{
return isset($this->vars[$key]) ? $this->vars[$key] : (isset($this->_vars[$key]) ? $this->_vars[$key] : false) : false;
}
function __set($key,$val)
{
$this->_vars[$key] = $val;
return true;
}
function bold($key)
{
return '<strong>' . $this->$key . '</string>';
}
}
The reason we keep this seperate is so it has its own space to run in, you just load your tpl file as an include in your constructor so it only can be loaded once, then when the file is included it has access to all the data and methods within TemplateLoader.
Index.php
<?php
require_once 'includes/Template.php';
require_once 'includes/TemplateLoader.php';
$Template = new Template();
$Template->foo = 'somestring';
$Template->bar = array('some' => 'array');
$Template->zed = new stdClass(); // Showing Objects
$Template->output('index'); // loads templates/index.php
?>
Now here we dont really want to mix html with this page because by seperating the php and the view / templates you making sure all your php has completed because when you send html or use html it stops certain aspects of your script from running.
templates/index.php
header
<h1><?php $this->foo;?></h1>
<ul>
<?php foreach($this->bar as $this->_foo):?>
<li><?php echo $this->_foo; ?></li>
<?php endforeach; ?>
</ul>
<p>Testing Objects</p>
<?php $this->sidebar = $this->foo->show_sidebar ? $this->foo->show_sidebar : false;?>
<?php if($this->sidebar):?>
Showing my sidebar.
<?php endif;?>
footer
Now here we can see that were mixing html with php but this is ok because in ehre you should only use basic stuff such as Foreach,For etc. and Variables.
NOTE: IN the TemplateLoader Class you can add a function like..
function bold($key)
{
return '<strong>' . $this->$key . '</string>';
}
This will allow you to increase your actions in your templates so bold,italic,atuoloop,css_secure,stripslashs..
You still have all the normal tools such as stripslashes/htmlentites etc.
Heres a small example of the bold.
$this->bold('foo'); //Returns <strong>somestring</string>
You can add lots of tools into the TempalteLoader class such as inc() to load other tpl files, you can develop a helper system so you can go $this->helpers->jquery->googleSource
If you have any more questions feel free to ask me.
----------
An example of storing in your database.
<?php
if(false != ($data = mysql_query('SELECT * FROM tpl_catch where item_name = \'index\' AND item_save_time > '.time() - 3600 .' LIMIT 1 ORDER BY item_save_time DESC')))
{
if(myslq_num_rows($data) > 0)
{
$row = mysql_fetch_assc($data);
die($row[0]['item_content']);
}else
{
//Compile it with the sample code in first section (index.php)
//Followed by inserting it into the database
then print out the content.
}
}
?>
If you wish to store your tpl files including PHP then that's not a problem, within Template where you passing in the tpl file name just search db instead of the filesystem
$products = array('...');
function parse_products($matches)
{
global $products;
$str = '';
foreach($products as $product) {
$str .= str_replace('%product_name%', $product, $matches[1]); // $matches[1] is whatever is between {products} and {/products}
}
return $str;
}
$str = preg_replace_callback('#\{products}(.*)\{/products}#s', 'parse_products', $str);
The idea is to find string between {products} and {products}, pass it to some function, do whatever you need to do with it, iterating over $products array.
Whatever the function returns replaces whole "{products}[anything here]{/products}".
The input string would look like that:
Requested products: {products}%product_name%{/products}