Currently I have the code below which registers a user.
It doesn't check to see if the username currently exists or anything like that, that is something that I want to implement.
I've never known how to use php objects and forms together. Any help will be much appreciated.
register.php
The page checks to see if a user is already logged in, either way the form is still displayed and submits to itself. The database access details are stored in config.php as constants.
<?php
session_start();
include("includes/config.php");
if(isset($_SESSION['username'])) {
echo "You are currently logged in as: " . $_SESSION['username'];
echo "<br />";
include("nav.php");
echo "<hr />";
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Register</title>
</head>
<body>
<?php
$odb = new PDO("mysql:host=" . DB_SERVER . ";dbname=" . DB_NAME, DB_USER, DB_PASS);
if (isset($_POST['firstName'])) {
$firstName = $_POST['firstName'];
$lastName = $_POST['lastName'];
$username = $_POST['username'];
$password = $_POST['password'];
$password = md5(DB_SALT.$password);
$type = $_POST['type'];
$date=date("Y-m-d");
$time=date("H:i:s");
$sql = "INSERT INTO tblMembers (firstName, lastName, username, passwordHash, type, joinedDate, joinedTime, lastActiveDate, lastActiveTime) VALUES (:firstName, :lastName, :username, :passwordHash, :type, :joinedDate, :joinedTime, :lastActiveDate, :lastActiveTime);";
$query = $odb->prepare($sql);
$results = $query->execute(array(
":firstName" => $firstName,
":lastName" => $lastName,
":username" => $username,
":passwordHash" => $password,
":type" => $type,
":joinedDate" => $date,
":joinedTime" => $time,
":lastActiveDate" => $date,
":lastActiveTime" =>$time
));
}
?>
<form method="post" action="">
Name: <input type="text" id="firstName" name="firstName" value="Michael" /><br />
Last Name: <input type="text" id="lastName" name="lastName" value="Norris" /><br />
Username: <input type="text" id="username" name="username" value="mstnorris" /><br />
Password: <input type="password" id="password" name="password" value="password" /><br />
Type: <input type="text" id="type" name="type" value="4" /><br />
<input type="submit" value="Add" />
</form>
</body>
</html>
I know how to write php objects using classes. This is what I had previously although I have been told that the methods I used are outdated. If anyone can shed any light on how to update it, it sure would help.
<?php
require_once("database.php");
class Member extends DatabaseObject {
protected static $table_name = "tblMembers";
var $firstName = "Mike"; // initiating the $firstName variable
var $lastName = "Norris"; // initiating the $lastName variable
var $username = "mstnorris"; // initiating the $username variable
var $password = "password"; // initiating the $password variable
var $reviews = "0"; // initiating the $reviews variable
var $type = "4"; // initiating the $type variable
function __construct($firstName, $lastName, $username, $password, $reviews, $type) {
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->username = $username;
$this->password = $password;
$this->reviews = $reviews;
$this->type = $type;
//$this->insert($firstName, $lastName, $username, $password, $type);
}
function set_firstName($firstName) {
$this->firstName = $firstName;
}
function get_firstName() {
return $this->firstName;
}
function set_lastName($lastName) {
$this->lastName = $lastName;
}
function get_lastName() {
return $this->lastName;
}
function get_fullName() {
if (isset($this->firstName) && isset($this->lastName)) {
return $this->firstName . " " . $this->lastName;
} else {
return "";
}
}
function set_username($username) {
$this->username = $username;
}
function get_username() {
return $this->username;
}
function set_password($password) {
$this->password = md5(DB_SALT.$password);
}
function get_password() {
return $this->password;
}
public static function authenticate($username="", $password="") {
global $database;
$username = $database->escape_value($username);
$password = $database->escape_value($password);
$passwordHash = md5(DB_SALT.$password);
$sql = "SELECT * FROM tblMembers ";
$sql .= "WHERE username = '{$username}' ";
$sql .= "AND passwordHash = '{$passwordHash}' ";
$sql .= "LIMIT 1";
$result_array = self::find_by_sql($sql);
if (!empty($result_array)) {
//echo "true";
return array_shift($result_array); // Pulling first element from array
} else {
//echo "false";
return false; // Ability to ask whether we return something
}
}
public function insert($firstName, $lastName, $username, $password) {
$database = new Database();
$database->query("INSERT INTO tblMembers VALUES ('','{$firstName}','{$lastName}','{$username}','{$password}','4')");
}
// Common Database Methods
private static function instantiate($record) {
$object = new self;
foreach ($record as $attribute=>$value) {
if ($object->has_attribute($attribute)) {
$object->$attribute = $value;
}
}
return $object;
}
public static function find_all() {
return self::find_by_sql("SELECT * FROM ".self::$table_name);
}
public static function find_by_id($id=0) {
global $database;
$result_array = self::find_by_sql("SELECT * FROM ".self::$table_name." WHERE userID={$id} LIMIT 1");
if (!empty($result_array)) {
return array_shift($result_array); // Pulling first element from array
} else {
return false; // Ability to ask whether we return something
}
}
public static function find_by_sql($sql="") {
global $database;
$result_set = $database->query($sql);
$object_array = array();
while ($row = $database->fetch_array($result_set)) {
$object_array[] = self::instantiate($row);
}
return $object_array;
}
private function has_attribute($attribute) {
$object_vars = get_object_vars($this);
return array_key_exists($attribute, $object_vars);
}
}
?>
Can the MVC approach be used with AJAX? Also, with that in mind, the AJAX code I have used before in other projects use $_GET, is there any problems with this as the data is never being sent to the address bar? If so, how do I use $_POST with AJAX?
Mike:
your set a getter and a setter like this:
class Spam
{
public $attr;
public $var;
public $arg;
/* __construct, __set, and __get
these are all special functions
we know this from the double underscore */
function __construct ()
{
// construction code
}
function __set ( $arg0, $arg1 )
{
$this->$arg0 = $arg1;
}
function __get ( $arg )
{
return $this->$arg;
}
}
and you would call it from your code as follows:
// this calls the __constructor function
$barney = new Spam();
// this calls the __set function
$barney->attr = "garnished with spam & eggs";
// this calls the __get function
$attrValue = $barney->attr;
This reduces the need to call a different method to set/get the values of your variable. This will only work on public variables as private and protected variables cannot be accessed from outside of your class.
Also, it is a good idea to have separate views, models, and controllers. Your controller is the script that the form submits to, your model is the class that is instantiated, and your view is where the user sends the information from. This will make your code easier to understand, rather than having your controller and view together.
Are you restricted to PHP4 for some reason? Or did you download some really old code and you're now trying to get it to work?
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[ UPDATE 2.27.2013 ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
OOP PHP Programming in Conjunction with JavaScript AJAX technology
Model-View-Controller:
MVC is not specific to PHP. MVC is a software design pattern that aims to solve a maintainability problem in code that combines separate
components of the code in ways that make the code less readable and
hard to maintain, which in the end is also a security risk.
Model-View-Controller is typically implemented via frameworks. In
regards to PHP there are frameworks available such as Zend,
CodeIgniter, CakePHP, etc. There frameworks implement the model view
controller through the document tree, although you can create your own
PHP framework (which isn't a good idea given your new to the
language), its probably better to use one that has already been
around. These frameworks may also enforce their own standards that result
in better code.
To understand a maintainable MVC framework you should be familiar with coding a website > > entirely in PHP. That means you should be using PHP classes [modules|models] to
dynamically generate the HTML pages[the view] depending what the user has done[the
controller file controls the model].
You question is very vague and its hard to tell what your asking, however, I get the
impression you're unable to figure out what MVC is and how to use it. Suppose you've
just created a layout for a website you will be developing. Since it
isn't possible to predict the size of your user's screen, you're
layout was designed in the browser. Your layout [or template if you
will] should be standard compliant HTML5 or XHTML. It should not be
constructed with images. Some people may disagree with me on this but
with the exception of your logo/header(though some use text for this
too), you should not have any tags are part of your
template(this is before any content has been written, obviously you'll
probably want to use a lot of images in your content). Your view at
this point should be HTML and CSS - any images that are a part of your
layout (ie patterns, backgrounds, anything layout specific) should be
in the CSS of your website. This is kind of the same reason that we
use the MVC pattern - it separates what should be separate.
You take your layout as the HTML and you write a PHP class[module]
that contains functions, for example we'll use
$view->showLeadboard();, $view->showAds(); $view->showFooter();
$view->setTitle("Title");, $view->setDescription("Description");...
This assumes that you've instantiated your class. Perhaps you don't
want to instantiate a class and you'd prefer to use static methods,
the choice is yours but you should understand what you're doing well
enough to have good reasons for doing it.
Now that your view is held inside of a PHP module you can worry about
your content. Chances are, if your website is dynamic, there will be
multiple pages and locations on those pages that contain dynamic
content from a database, or forms (we're still inside of the view)
that submit data to the controller.
Suppose somebody is registering at your website. The go to your
domain and a view is generated based on the request to
www.site.com and the view that is generated is the index page. This person who has come to your page has decided to register for an
account with your service. They click on the "register" hyperlink and
another view is generated that displays a form for them to create
their login credentials. They fill the form out click submit. The
information supplied in the form is submitted to a controller(we're
not talking about ajax or implementing an MVC design pattern for our
javascript code right now), we'll say that the view
site.com/register submits to the controller site.com/engine/process.php. Process.php filters/sanitizes the user data from the form and instantiates the correct class(model,
we'll call this one new User) that will then make a database
call through one of its methods, or maybe even through its
constructor(you should be aware of the magic methods available to you
in PHP) and this the result of this query mutates the view to be
slightly different depending on what the controller told the model and
what the model told the view.
I don't even know what I can say about your question regarding AJAX - given your position with PHP I'm going to guess that you're using JQuery for ajax calls. If this is the case you do not need to implement a model-view-controller from your jquery files, you can just create a jquery script and then add a method to your view that calls that script and implements it.
All in all if you are struggling to understand what a common pattern like MVC is and how to use it you should really go back to the basics. I can't stress enough that the online tutorials aren't going to help you if you don't understand why the author used the solution that they used and chances are they're not explaining that to you because its sometime simple that you should be able to understand yourself provided you have a basic understanding of the php language, its syntax, and how to solve problems with it. This all comes just from spending time with the language, learning how it works, and learning what it doesnt do well and what it does do well.
Ok, you have a couple of questions wrapped into one large question but I'll try to answer them as best as I can. I'll answer them in the order of importance.
How do you update your class(es).
How to structure forms better.
How to check login status.
Most applications now use some form of an MVC architecture. Models, Views, and Controllers are a way of separating responsibilities to classes. Here's a brief tutorial on MVC architecture for PHP. With that said, there are a number of open source frameworks that you can use like, Zend, CakePHP and more.
Try using one of the strategies for MVC or try a framework.
Try not to have the form self submit to itself. Instead route it to a seperate page and handle the logic there. Also you can wrap your inputs into and array by using the [] notation. For example: <input type="text" name="user[firstname]" />
However If you are just doing a login form, then all you need is some unique form of identification and a credential (e.g. username and password).
There are several ways to persist users' login status, chiefly used are sessions and cookies. Storing the entire model in the session or cookie is usually frowned upon. Instead try storing the username and a unique key that you can compare against in a database.
Using cookies gives you more control over how long you want the session to last.
Related
Good Day Everyone, Sorry if i made a lot of mistakes in my code but i am new to object oriented programming in PHP as i heard it is easily readable and organizes code.
I am trying a first project by working on a Login Script with mysql database.
The issue is i have written my functions but can seem to get it to work and i am not getting any errors to use to debug. Below are my codes.
I have a database.php file that contains most functions
class Database
{
//Database conn properties
private $host = 'localhost';
private $user = 'root';
private $pass = 'password';
private $dbname = 'rtmdb';
private $dbh;
private $error;
private $stmt;
public function __construct()
{
//Function for database connection
//Set DSN
$dsn = 'mysql:host='. $this->host . ';dbname'. $this->dbname;
//Set Options include persistent connection
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
//Create new PDO Instance
try
{
$this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
}
catch(PDOException $e)
{
$this->error = $e->getMessage();
}
}
public function query($query)
{
//#param function for executing insert, select, update
$this->stmt = $this->dbh->prepare($query);
if(!$this->stmt)
{
echo $this->dbh->lastErrorMsg();
}
else
{
return $this->stmt = $this->dbh->prepare($query);
}
}
public function bind($param, $value, $type = null)
{
if(is_null($type))
{
switch(true)
{
case is_int($value):
$type = PDO::PARAM_INT;
break;
case is_bool($value):
$type = PDO::PARAM_BOOL;
break;
case is_null($value):
$type = PDO::PARAM_NULL;
break;
default;
$type = PDO::PARAM_STR;
}
}
$this->stmt->bindValue($param, $value, $type);
}
public function clean_str($data)
{
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
$data = str_replace("'", "’", $data);
return $data;
}
public function execute()
{
return $this->stmt->execute();
}
public function lastInsertId()
{
$this->dbh->lastInsertId();
}
public function resultset()
{
$this->execute();
return $this->stmt->fetchAll(PDO::FETCH_ASSCO);
}
public function registerAdmin($fname, $lname, $oname, $uname, $email, $idnumber, $pass, $profimg, $status)
{
$email = $this->clean_str($email);
$lname = $this->clean_str($lname);
$email = $this->clean_str($oname);
$lname = $this->clean_str($uname);
$email = $this->clean_str($email);
$lname = $this->clean_str($idnumber);
$email = $this->clean_str($pass);
$lname = $this->clean_str($profimg);
$email = $this->clean_str($status);
$database->query('INSERT INTO admin (fname, lname, oname, uname, email, idnumber, pass, profimg, status) VALUES(:fname, :lname, :oname, :uname, :email, :idnumber, :pass, :proofimg, :status)');
$database->bind(':fname', $fname);
$database->bind(':lname', $lname);
$database->bind(':oname', $oname);
$database->bind(':uname', $uname);
$database->bind(':email', $email);
$database->bind(':idnumber', $idnumber);
$database->bind(':pass', $pass);
$database->bind(':profimg', $profimg);
$database->bind(':status', $status);
$database->execute();
if(!$database->lastInsertId())
{
die('Yawa Don Gas: ' . $this->dbh->lastErrorMsg());
}
$this->dbh->close();
}
public function loginAdmin($uname, $pass)
{
$uname = $this->clean_str($uame);
$pass = $this->clean_str($pass);
$database->query('SELECT * FROM admin WHERE uname = :uname AND pass = :pass');
$database->bind(':uname', $uname);
$database->bind(':pass', $pass);
$results = $database->execute();
$count = mysql_num_rows($results);
if ($count == 1)
{
$rows = $database->resultset();
foreach($rows as $row)
{
$id = $row['id'];
$uname = $row['uname'];
$pass = $row['pass'];
}
if(!isset($uname) or empty($uname))
{
echo 'Invalid Usernmae';
}
elseif(!isset($pass) or empty($pass))
{
echo 'Invalid Password Details';
}
else
{
echo 'Good';
$set = $this->crossEncryption(ENCRYPT_KEY, 10).$id;
setcookie('itravel', $set, time()+COOKIE_EXPIRE, COOKIE_PATH);
}
return;
$this->dbh->close();
}
}
public function crossEncryption($key,$length)
{
$characters = $key;
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, strlen($characters) - 1)];
}
return $randomString;
}
public function logout()
{
if(isset($_SESSION['uname']))
{
unset($_SESSION['uname']['id']);
session_destroy();
header('Location: index.php');
}
}
}
I have another travelapis.php file
<?php
require_once 'database.php';
class travelapis
{
public function __construct()
{
$this->dbh = new Database;
}
public function login()
{
if(isset($_POST['uname']))
{
$uname = $_POST['username'];
$pass = $_POST['password'];
if(empty($uname) || empty($pass))
{
echo 'Please Fill in all Fields';
}
else
{
$this->dbh->login($uname, $pass);
}
}
}
}
Then also a login.php file to carry out the function
<?php
require_once "travelapis.php";
$api = new travelapis;
$api->login();
This is used in the form action. For some reason i really don't understand, this doesn't seem to work. Any help would to as i need to wrap my head around OOP with PHP
The main issues I can spot, in no particular order:
You don't really have an object oriented design. You have a single Database class that does everything. It's mostly procedural code where Database plays the role of index.php. I'd expect classes for each different concept involved: database connection, database result, administrator... And maybe some design pattern that helps with application flow (such as Model-View-Controller). What will you do when you need to implement e.g. a contact form? Add new methods to your megaclass?
You're actively preventing proper error handling: try/catch on connection to hide the exception, die() in the middle of nowhere
Methods are unpredictable: they return stuff or print to stdout (often both) without a hint.
You have hard-coded global variables popping up from nowhere in some methods (e.g. login().
clean_str() has no reason to exist. If you want to keep it, give it a better name like randomlyCorruptInputData().
The database features of the class do not really have any advantage over using raw PDO. It actually makes it harder because you need to learn a new API and some PDO features become unavailable.
In spite of all my comments below, it looks like you are learning OO. Keep working on it. I'm not necessarily going to find your bug for you, but rather push you forward. After you have revised some of your code to handle the stuff below, the bug may vanish.
Something to think about in designing OO code:
It should not be a thin layer. (Else, why bother?)
It should isolate the implementation end from the business-end.
The user of the OO package should not necessarily need to understand the underlying processes.
Related to that last item:
Consider doing travelapis::login from within travelapis::__construct.
The caller should not have to understand prepare-bind-execute-inserted_id -- See if you can roll those together into a single call.
Ultimately, the business-end should not even know what "tables" exist, much less how many exist. It should say "put/get" these things into/from the database. The package would then take care of JOINing tables, iterating, etc; thereby hiding the schema from the business-end.
A select script should simply return an array of results. Perhaps 2 versions -- an array of arrays versus an array of hashes (associative arrays).
Now for some nit-picks / bugs...
Don't prepare twice.
Don't stripslashes; they will already be gone (unless you erroneously doubled up on addslashes).
Don't htmlspecialcharacters except when immediately putting in HTML.
Consider extending PDO instead of having to always say $this->dbh->
Consider adding something. Why mimic inserted_id when you could have that returned from the query execution (for example).
Don't bother with mysql_num_rows if you can just as easily do count($rows)
Bug with lots of $lname= and $email=
clean_str is probably totally useless. Maybe trim is useful; bind does what mysql needs; the rest is "wrong".
There is some code after a return;??
empty checks for isset.
First off, all of the previous answers have really valid and constructive comments.
I am going to assume that you are fairly new to php and OOP. That being said this is not something that you are just going to spend a night coding and be done with.
However, you still need to write a login script from start to finish. Then you need to evaluate your project and determine where you had problems or struggled trying to get something accomplished. Then you need to come up with a way to do it better,which is usually just a result of more simplified and structured logic.
Let's look at this from a login system point of view. What do you have to do to log someone in. Let's look at what it is you are truly dealing with.
Keeping it simple you will be dealing with:
Users
Passwords
Validations
Formatting
Errors
Hint - Each one of these will end up being a class that handles those things. Not only will the classes deal with those things, but they will deal exclusively with those categories and will be called whenever you need to do any of the above things.
I will show you a very simple example. When you make your login form you are going to most likely have two inputs, a username and a password. You are going to want to validate those inputs for a few things. Like, for example, are the username and passwords blank, or long enough.
So you would make a validation class that contains functions that will check and validate those conditions. Like so:
class Validate{
public function __construct(){
}
//Just testing to see if it is empty. You can add any other criteria to this that you want.
public function userName($userName){
if(isset($userName) && $uerName){
return TRUE;
}else{
return FALSE;
}
}
//Just testing to see if it is empty. You can add any other criteria to this that you want.
public function password($password){
if(isset($password) && $password){
return TRUE;
}else{
return FALSE;
}
}
}
Now to use this just call the class Validate and pass your username and password to check if they are valid.
$valid = new Validate();
if(!$valid->userName($_POST['username'])){
echo 'Sorry, There is something wrong with your username.';
}
if(!$valid->password($_POST['password'])){
echo 'Sorry, There is something wrong with your password.';
}
Here are where classes are really cool. Eventually you are going to want to validate many different things, emails, phone numbers, names, addresses, ect.. Just add a new function to your Validate class and anytime you want to validate you just call your class and the function you require, like valid->email()
Even better yet, you know exactly where your code is so when you realize you need to change how something gets validated you make your edits in the class in one function and it works across your entire code base.
Like I said before, you will make an individual class for all those categories. I think after tinkering around you will see how this is huge plus.
Another thing is not to get discouraged. It's called learning.. You will make mistakes and you will earn from those mistakes. The important thing is to just keep coding.
Hope this helps you. Good luck!
PHP student here Consider the following 2 methods the 1 method checks if a user exists the other registers a user.
public function is_registered($userEmail)
{
$this->email = $userEmail;
$sql = "SELECT * from users WHERE email = :email";
$stmnt = $db->prepare($sql);
$stmnt->bindValue(':email', $userEmail);
$check = $stmnt->execute();
if($check >= 1) {
return true;
}
else {
return false;
}
}
public function register_user($email, $pword, $firstname, $lastname)
{
$this->email = $email;
//call method is_registered inside register user class
$registered = $this->is_registered($email);
if($registered == true){
die("USER EXISTS");
}
else {
//continue registration
}
}
Although this might not be the best use case example I basically want to know:
Is "normal / good practice" to call a method inside a method. Another use case might be calling a get_email() method inside a login() method or similar method where you need an email address.
What is the difference if I set a property inside a method or just access the passed parameter directly? Example:
Method with set property
public function is_registered($userEmail)
{
$this->email = userEmail // SET PROPERTY
$sql = "SELECT * from users WHERE email = :email";
$stmnt = $db->prepare($sql);
$stmnt->bindValue(':email', $userEmail);
}
Method with no set property.
public function is_registered($userEmail)
{
//NO SET PROPERTY
$sql = "SELECT * from users WHERE email = :email";
$stmnt = $db->prepare($sql);
$stmnt->bindValue(':email', $userEmail);
}
Hope this makes sense, any help or guidance much appreciated.
On the point of view of OOP, both approaches are kinda weird. Since your User class doesn't seem to be static, and since the e-mail address is one of the major uniqueness discriminant for authentication, your class should be instantiated with a valorized email property that never changes... either upon database extraction (1) or form filling (2):
$user = new User(..., $auth->email); (1)
$user = new User(..., $_POST['registration_mail']); (2)
On the top of that, a method named is_registered should really not mess with assignments. All it should do is to check whether the current User instance class is defined in your database or not.
In your first approach, the risk is to mess up everything. Let's suppose you have the following user:
$user = new User('John', 'john#domain.com');
Now, let's see what happens when, by mistake, you pass the wrong email as argument:
$result = $user->is_registered('marley#domain.com');
echo $user->name; // John
echo $user->email // marley#domain.com
In your second approach, you should not allow the is_registered to accept any argument since, as I explained you before, that property should be defined upon creation to avoid fatal mistakes. Let's bring back the same user we used in the first example:
$user = new User('John', 'john#domain.com');
Now, let's see what happens when, by mistake, you pass the wrong email as argument (john#domain.com is registered, marley#domain.com isn't):
$result = $user->is_registered('marley#domain.com'); // false
So my suggestion is, initialize the property upon the creation of the instance and never mess with it. Alternatively, you could implement a static function into a utility class that, for a given email, performs the desired check. But try to make your OOP design as strict as possible.
I know, globals not (;
I am new to OOP, and I'm refactoring some functions I created into classes, but I come to a problem. Some of my classes are called from the pages themselves that the users enter (example: $Link->create('page/to/go');). Since this is outside any class, there's no problem, the links get created.
But then, I have a class that attempts to login the user when created, and if the email entered is not in the database it redirects the user to the register page. Obviously, only doing header ('Location '.$Link->create('page/to/go')) does not work.
What I would do is to set the create method as static and then call it from everywhere. But I think this would be similar to using globals and I am trying to correct bad habits. So how should I do this?
Here's some of the code for the class Link, implementing a 404-detect that I explained here:
class Link
{
private function valid($check)
{
$exceptions=array("help/report", "translate"); // More pages and rules to be added
return in_array($check,$exceptions);
}
public function create($arg)
{
if (!file_exists("/path/to/".$arg) && !$this->valid($arg))
{
// Call a function to store the error in a database.
error ("404 for ".$arg);
// One way of handling it. Replace '/' for ' ' and google that string in this page.
$arg=str_replace("/","%20",$arg);
return "https://www.google.com/#q=site%3A".Configuration::get('BaseUrl')."%20".$arg;
}
else
{
// If the page exists or is an exception, create the normal link.
if(empty($arg)) return Configuration::get('BaseUrl');
else return Configuration::get('BaseUrl').$arg;
}
}
}
As you can see in the code, when I implement error() into a class I will have a similar problem.
One option I just thought is that I might want to return an error and parse it from outside the __construct() of the User class. But it only works with this, as it's a yes/not, and I don't think making a error code up is proper for other cases.
So, what is your suggestion for passing properties and methods from one classes to others? Is it okay to use static for this context?
EDIT. The difficulty of my question it's that, almost all book, tutorial, page etc I've seen talks about how to create a SINGLE class. I haven't seen any explaining deeply how classes should talk to each other.
EDIT 2. As requested in the comments, here goes some more code. The user accesses his courses entering only the email (getting a level 1), while the user can only edit his settings if he gets a level 2 in the settings page. Not finished as I'll put some more methods.
class User
{
private $Email;
private $Name;
public function __construct()
{
if (!empty($_POST['logout'])) session_destroy();
else if ( !empty($_POST['email']) )
{
$this->loginEmail($_POST['email']);
}
else if ( $_SESSION['level'] == 1 )
{
if (!empty($_POST['password']))
{
$this->loginFull($_SESSION['email'],$_POST['password']);
}
else
{
$this->loginEmail($_SESSION['email']);
}
}
else if ( $_SESSION['level'] == 2 )
{
$this->loginFull($_SESSION['email'],$_SESSION['pass']);
}
else session_destroy();
}
private function loginEmail($Email)
{
$sql=mysql_query("SELECT * FROM users WHERE email='".mysql_real_escape_string($Email)."'"); //Retrieve the entries from the database
$row=mysql_fetch_assoc($sql);
if(mysql_num_rows($sql)==1)
{
$this->getData($row);
$_SESSION['level']=1;
}
else header ('Location: http://example.org/new/student/');
}
private function loginFull($Email,$Pass)
{
$sql=mysql_query("SELECT * FROM users WHERE email='".mysql_real_escape_string($Email)."' AND pass='".md5($Pass)."'"); //Retrieve the entries from the database
$row=mysql_fetch_assoc($sql);
if(mysql_num_rows($sql)==1)
{
$this->getData($row);
$_SESSION['pass']=$Pass;
$_SESSION['level']=2;
}
else $this->loginEmail($Email);
}
private function getData($row)
{
$_SESSION['email']=$row['email'];
$this->Email=$row['email'];
$this->Name=$row['name'];
}
public function get($Var)
{
return $this->$Var;
}
}
And now the class Error. As you can see, I already performed some DI without even knowing about it here.
class Error
{
private $Page;
private $Language;
private $User;
public function __construct($Page,$Language,$User="None")
{
$this->Page=$Page;
$this->Language=$Language;
$this->User=$User;
if (!empty($_REQUEST['banner']))
$this->Banner=$_REQUEST['banner'];
}
public function add($Kind)
{
if (!mysql_query("INSERT INTO error (kind, page, lang, user, version, date) VALUES ('".mysql_real_escape_string($Kind)."', '".mysql_real_escape_string($this->Page)."', '".mysql_real_escape_string($this->Language)."', '".mysql_real_escape_string($this->User)."', '".Configuration::get('Version')."',NOW() )"))
mail(Configuration::get('ErrorEmail'), "Error '".$Kind."' that couldn't be stored.",
"Full url: ".$FullUrl."\n Language: ".$this->Language->Lang."\n User: ".$Identif."\n Version: ".$Version); // Inform of the error by email
}
}
Create instance of Link class and pass it to where it is needed (using setter or constructor).
Definitelly read something abou DI (Dependency Injection) and then DI Containers.
Nice introduction in Nette Framework - Dependency Injection
Singletons and Static aren't a good choice. In the end everything falls onto the globals problem.
You should inject your link helper into the classes by constructor or setter (DI as #jasir said).
If you'll redirect the user, you can also inject an redirector helper:
$redirector->redirect('controller','action', array('my','params'));
Hint: this is bad too Configuration::get(). Inject the config instead.
And always remember: Don't look for things!
I'm using Zend_Auth with a project using doctrine.I believe every bootstrapping is done correctly and i can log in.
my adapter looks like this:
class Abra_Auth_Adapter_Doctrine implements Zend_Auth_Adapter_Interface {
protected $_resultArray;
private $username;
private $password;
public function __construct($username, $password) {
$this->username = $username;
$this->password = $password;
}
//based on feedbacks as response authenticate has changed to this
public function authenticate() {
$q = Doctrine_Query::create()
->from("Abra_Model_User u")
->leftJoin("u.Role r")
->where("u.username=? AND u.password=?", array($this->username,$this->password));
$result = $q->execute();
if (count($result) == 1) {
return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $result->get("Mylibrary_Model_User"), array());//autoloaderNamespaces[] = "Mylibrary_" in application.ini
} else {
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, null, array("Authentication Unsuccessful"));
}
}
my Abra_Controller_Pluging_Acl looks like this
class Abra_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
parent::preDispatch($request);
$controller = $request->getControllerName();
$action = $request->getActionName();
$module = $request->getModuleName();
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity()){
$identity = $auth->getIdentity();
$roles = $identity["Role"];
$role = $roles["name"];
$role = (empty ($role) || is_null($role))? "regular" : $role ;
} else {
$role = "guest";
}
}
now having Doctrine_Event Fatal error: spl_autoload() [function.spl-autoload]: Class Doctrine_Event could not be loaded. i've seen this post here and i'm wondering how that can affect my using of Zend_Session, and it's true that i have apc.dll enabled in my php.thanks a lot for reading this
How to get the role: In your adapter, on successful login, rather than returning only the username field, how about returning the whole user object? Then the whole thing will be available when you call Zend_Auth::getIdentity().
Question 1: If you treat controllers as resources and the ACL rules are going to be different per module, then the resource names should reflect the module, as well. This will address the issue of modules with identical controller names.
Question 2: I am not sure I am understanding correctly. Zend_Auth and its storage will take care of keeping the uer identity in its own session namespace. However, I have run into the issue of what to do when the user record in the db changes - say, the user modifies his full name in his profile during his logged-in session - and you are displaying that full name in your site template, pulled from Zend_Auth::getIdentity(). As a user, I would expect the change to be reflected in the visible interface, but the change has only occurred back in the db, not in the session.
What I have done in the past is to create an additional auth adapter that fetches the new user record and always returns success. When the user updates his profile, I call Zend_Auth::authenticate() using this trivial adapter. The session storage gets updated and all is well with the world.
[This approach is almost certainly a hack, so I'd be interested in hearing alternative approaches. I'm sure I can set a value in the session storage directly, but when I last tried it, I couldn't make it quite work. So resorted to the additional adapter workaround.]
I've built a class called Login with a construct that either logs them in or it doesn't... I also have a static function called isAuthenticated which is meant to check if the user is logged in or not... I've been messing around with static functions etc but can't seem to get what I want.
Ideally, it'd be where I can easily go
<?php if (Login::isAuthenticated()) { ?>
Sign Out
<?php } ?>
Here is my class so far... Complete with my attempts..
class Login
{
private static $_auth;
public function __construct($username, $rawPassword) {
global $db;
require('edit/users/config.php');
$hashedPassword = sha1(SALT . $_POST['password']);
$query = 'SELECT firstname FROM users WHERE user = "' . $db->cleanString($username) . '" AND pass = "' . $db->cleanString($hashedPassword) . '" LIMIT 1';
$login = $db->query($query);
if ($login) {
$_SESSION['username'] = $username;
self::$_auth = true;
header('Location: ' . CONFIG_DIR_BASE);
} else {
ErrorHandler::addErrorToStack('Your username and/or password did not match one on our system. ');
}
}
public static function isAuthenticated() {
return self::$_auth;
}
}
Thank you very much!
Since HTTP is stateless, your class' static variable ($_auth) won't 'survive' between pageloads, so if you're trying to make the variable stick, you'll need to store it as a Session variable.
However, I would strongly encourage you to not write your own auth class unless you are really serious about it. There are dozens of excellent PHP auth scripts out there to pick from, that have already addressed all the intricacies of web authentication.