Recently, I've been wanting to implement the Facebook SDK for PHP in my CodeIgniter project.
Facebook sdk can be slooooow, that's why I want to store a class instance containing gathered fb & fb user details in the user session.
When I store the class instance, I can use it later on as long as I don't refresh or redirect.
When I do redirect, the value is unset...
I've read about using serialize and unserialize (for global PHP sessions), but it didn't help in this situation.
This is the fb class:
class FBClass {
protected $FB = false;
protected $FBUser = false;
protected $FBUserProfile = false;
protected $FBUserEmail = false;
protected $loggedIn = false;
protected $config = array(
'appId' => '007',
'secret' => '911',
'cookie' => true,
'fileUpload' => false,
'allowSignedRequest' => false
);
protected $params = array(
'client_id' => '007',
'scope' => 'email'
);
function __construct() {
if (!$this->FB) {
$this->FB = new Facebook($this->config);
}
}
public function isLoggedIn() {
return $this->loggedIn;
}
public function getLoginUrl() {
$this->FB->getLoginUrl($this->params);
}
public function getUser() {
if (!$this->FBUser) {
$this->FBUser = $this->FB->getUser();
}
return $this->FBUser;
}
public function getUserProfile() {
if (!$this->FBUserProfile) {
$this->FBUserProfile = $this->FB->api('/me','GET');
}
if ($this->FBUserProfile && !$this->FBUserEmail) {
$emailArray = $this->FB->api('/me?fields=email');
$this->FBUserEmail = array_key_exists('email', $emailArray) ? $emailArray['email'] : 'Onbekend';
$this->loggedIn = true;
}
return $this->FBUserProfile;
}
public function getUserFullName() {
return $this->FBUserProfile['name'];
}
public function getUserAlias() {
return $this->FBUserProfile['username'];
}
public function getUserEmail() {
return $this->FBUserEmail;
}
public function getUserFirstName() {
return $this->FBUserProfile['first_name'];
}
public function getUserLastName() {
return $this->FBUserProfile['last_name'];
}
public function getUserId() {
return $this->FBUserProfile['id'];
}
}
In my controller, I store or retrieve my FBClass instance like this:
public function checkFacebookState() {
if (!$this->session->userdata('fb')) {
$fbSes = new FBClass();
$this->session->set_userdata('fb', serialize($fbSes));
} else {
$fbSes = unserialize($this->session->userdata('fb'));
}
}
Storing strings in the session does work.
I know PHP is not OO, that's why I'm looking for an easy alternative.
Any ideas?
In order for you to save your instance in a session, there is no problem whether you serialize it first or not.
Take the following example for instance.
create a library test in your application/library folder:
class Test {
public $testProp;
public function __construct() {
$this->testProp = 'testing';
}
}
then in your controller write the following:
class Welcome extends CI_Controller {
public function index()
{
$this->load->library('test');
$this->session->set_userdata('someIns', $this->test);
$this->load->view('welcome_message');
}
}
and lastly in your view:
<div id="container">
<?php
echo '<pre>';
var_dump($x = $this->session->userdata('someIns'));
echo '</pre>';
echo '<pre>';
echo $x->testProp;
echo '</pre>';
echo '<pre>';
var_dump($this->session->all_userdata());
echo '</pre>';
?>
</div>
the output would be:
object(Test)#15 (1) {
["testProp"]=>
string(7) "testing"
}
testing
array(6) {
//some session data
["user_data"]=>
string(0) ""
["someIns"]=>
object(Test)#15 (1) {
["testProp"]=>
string(7) "testing"
}
}
if you noticed I used echo $x->testProp directly after fetching it from the session.
No serialization needed here.
With serialization:
Controller:
class Welcome extends CI_Controller {
public function index()
{
$this->load->library('test');
$this->session->set_userdata('someIns', serialize($this->test));
$this->load->view('welcome_message');
}
}
View:
<div id="container">
<?php
echo '<pre>';
var_dump($x = $this->session->userdata('someIns'));
echo '</pre>';
echo '<pre>';
$y = unserialize($x);
echo $y->testProp;
echo '</pre>';
echo '<pre>';
var_dump($this->session->all_userdata());
echo '</pre>';
?>
</div>
Results:
string(44) "O:4:"Test":1:{s:8:"testProp";s:7:"testing";}"
testing
array(6) {
//some session data
["user_data"]=>
string(0) ""
["someIns"]=>
string(44) "O:4:"Test":1:{s:8:"testProp";s:7:"testing";}"
}
the word testing is still being echoed out.
Now your problem, apparently, is that you are getting your FB class in a wrong way,
it is a library. Thus, you need to load your library first, as I did in the above example,
$this->load->library('test');
$this->session->set_userdata('someIns', $this->test);
or after serializing it. $this->test here is an instance of the Test class in the library folder.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I'm trying to grasp the concept of a datamapper (I hope this is the right terminology) in conjunction with protected properties.
I am building an authentication system. There I have a User class
class User {
protected $id;
public $first_name;
public $mail;
protected $password;
As you can see, I chose to make $id and $password protected. Actually I'm not quite sure if that's right, but I did read, that one should try to keep the scope of properties as closed as possible.
I also build a datamapper to save my user object to my database. The mapper is injected to the user class via constructor dependency injection. I call the mappers save-method from inside my user class this way
public function save () {
return $this->dep['mapper']->saveUser($this);
}
Inside my mappers saveUser()-method I am building an array of values to pass along to my database class.
public function saveUser($obj) {
$insert_array;
foreach ( $obj as $key => $value ) {
$insert_array[$key] = $obj->get($key);
}
This does not work the way it's intended, because my mapper is not able to iterate over the protected properties. Therefore these properties are not passed on to the database. If the said properties are public it works just fine.
So my question is: How do I have to setup my classes and methods so that my mapper is able to get all the values it needs, without exposing all my properties?
Extra: I already made use of __get() to circumvent the problem, but is that good coding practice?
There is no single right answer for this, but IMO you don't want to have different visibility for fields in a data object. Here are some ideas.
If you're set on having different visibility for fields on you User class, you can change things up like this to allow your Mapper to save the data using an array you build in the save method of your user class.
<?php
class User
{
protected $id;
public $first_name;
public $mail;
protected $password;
private $dep = [];
public function __construct()
{
$this->dep['mapper'] = new Mapper();
}
public function save()
{
$data = [
'id' => $this->id,
'first_name' => $this->first_name,
'mail' => $this->mail,
'password' => $this->password
];
return $this->dep['mapper']->saveUser($data);
}
}
class Mapper
{
public function saveUser($data)
{
foreach($data as $field=>$value)
{
echo $field.': '.$value.PHP_EOL;
}
}
}
$myUser = new User();
$myUser->first_name = 'Lando';
$myUser->mail = 'lando#cloudcity.gov';
$myUser->save();
A more formal option is to use a Data Transfer Object (DTO), which is a dead-simple class that just encapsulates the data. Then you can control access to the fields in your business object.
<?php
class User
{
private $dto;
private $dep = [];
public function __construct(UserDto $dto)
{
$this->dto = $dto;
$this->dep['mapper'] = new Mapper();
}
public function __get($propName)
{
if($propName=='password')
{
throw new Exception('No password for you');
}
elseif(property_exists($this->dto, $propName))
{
return $this->dto->$propName;
}
throw new InvalidArgumentException('No property '.$propName.' found in object');
}
public function __set($propName, $value)
{
if($propName=='id')
{
throw new Exception('ID may not be changed');
}
elseif($propName=='password')
{
throw new Exception('Password may not be changed');
}
elseif(property_exists($this->dto, $propName))
{
$this->dto->$propName = $value;
}
else
{
$this->$propName = $value;
}
}
public function __isset($propName)
{
return (property_exists($this->dto, $propName));
}
public function save()
{
return $this->dep['mapper']->saveUser($this->dto);
}
}
class UserDto
{
public $id;
public $first_name;
public $mail;
public $password;
}
class Mapper
{
public function saveUser(UserDto $dto)
{
foreach ($dto as $key => $value)
{
$insert_array[$key] = $dto->$key;
echo $key.': '.$value.PHP_EOL;
}
}
}
try
{
$dto = new UserDto();
$myUser = new User($dto);
$myUser->first_name = 'Lando';
$myUser->mail = 'lando#cloudcity.gov';
echo $myUser->password;
$myUser->password = 'foobar';
$myUser->save();
}
catch(Exception $e)
{
echo $e->getMessage().PHP_EOL;
}
A better option to control access to properties is by using get/set/has methods. This is verbose, but has the benefit of adding logic or transforms to the data as you get and set it. One of the major benefits of this approach is that full-featured code editors will code-complete all of these getters and setters, you don't get that with magic methods. You can of course use this in combination with DTOs.
<?php
class User
{
private $data = [
'id'=>null,
'first_name'=>null,
'mail'=>null,
'password'=>null
];
private $dep = [];
public function __construct($data)
{
$validData = array_intersect_key($data, $this->data);
foreach($validData as $currKey=>$currValue)
{
$this->data[$currKey] = $currValue;
}
$this->dep['mapper'] = new Mapper();
}
public function getId()
{
return $this->data['id'];
}
//Notice there is no setter for ID!
public function hasId()
{
return (!empty($this->data['id']));
}
public function getFirstName()
{
return $this->data['first_name'];
}
public function setFirstName($val)
{
$this->data['first_name'] = $val;
}
public function hasFirstName()
{
return (!empty($this->data['first_name']));
}
public function getMail()
{
return $this->data['mail'];
}
public function setMail($val)
{
$this->data['mail'] = $val;
}
public function hasMail()
{
return (!empty($this->data['mail']));
}
//Notice there is no getter for ID!
public function setPassword($val)
{
$hashed = md5($val); //Just an example, don't do this
$this->data['password'] = $hashed;
}
public function hasPassword()
{
return (!empty($this->data['password']));
}
public function save()
{
return $this->dep['mapper']->saveUser($this->data);
}
}
class Mapper
{
public function saveUser($data)
{
foreach($data as $field=>$value)
{
echo $field.': '.$value.PHP_EOL;
}
}
}
try
{
$dataFromDb = [
'id'=>123,
'first_name'=>'Lando',
'mail'=>'lando#cloudcity.gov',
];
$myUser = new User($dataFromDb);
$myUser->setFirstName('Chewie');
$myUser->setMail('wookie#kashyyyk.net');
if(!$myUser->hasPassword())
{
$myUser->setPassword('AAAAAARRRRRRGHHHH');
}
$myUser->save();
}
catch(Exception $e)
{
echo $e->getMessage().PHP_EOL;
}
I prefer to do something like this, where all of the verbose boilerplate is relegated to data access objects that encapsulate the data and handle loading and saving individual records, and the app logic for individual records is contained in the main business object. They can be superclasses or traits, whatever floats your boat. Personally, I have code that writes all of my DAO and business object classes for me based on database schemas, so all I have to worry about is app logic.
<?php
trait UserDao
{
private $data = [
'id'=>null,
'first_name'=>null,
'mail'=>null,
'password'=>null
];
private $deps;
public function getId()
{
return $this->data['id'];
}
//Notice there is no setter for ID!
public function hasId()
{
return (!empty($this->data['id']));
}
public function getFirstName()
{
return $this->data['first_name'];
}
public function setFirstName($val)
{
$this->data['first_name'] = $val;
}
public function hasFirstName()
{
return (!empty($this->data['first_name']));
}
public function getMail()
{
return $this->data['mail'];
}
public function setMail($val)
{
$this->data['mail'] = $val;
}
public function hasMail()
{
return (!empty($this->data['mail']));
}
private function _getPassword()
{
return $this->data['password'];
}
private function _setPassword($val)
{
$this->data['password'] = $val;
}
public function hasPassword()
{
return (!empty($this->data['password']));
}
public function load($data)
{
$validData = array_intersect_key($data, $this->data);
foreach($validData as $currKey=>$currValue)
{
$this->data[$currKey] = $currValue;
}
}
private function _save()
{
return $this->dep['mapper']->saveUser($this->data);
}
}
class User
{
use UserDao;
public function __construct()
{
$this->dep['mapper'] = new Mapper();
}
public function setPassword($val)
{
$hashed = str_rot13($val); //Just an example, don't do this
$this->_setPassword($hashed);
}
public function getPassword()
{
return str_rot13($this->_getPassword()); //Just an example, don't do this
}
public function save()
{
echo 'Do some complex validation here...'.PHP_EOL;
$this->_save();
}
}
class Mapper
{
public function saveUser($data)
{
foreach($data as $field=>$value)
{
echo $field.': '.$value.PHP_EOL;
}
}
}
try
{
$dataFromDb = [
'id'=>123,
'first_name'=>'Lando',
'mail'=>'lando#cloudcity.gov',
];
$myUser = new User();
$myUser->load($dataFromDb);
$myUser->setFirstName('Chewie');
$myUser->setMail('wookie#kashyyyk.net');
if(!$myUser->hasPassword())
{
$myUser->setPassword('AAAAAARRRRRRGHHHH');
}
$myUser->save();
echo 'Unfutzed Password: '.$myUser->getPassword().PHP_EOL;
}
catch(Exception $e)
{
echo $e->getMessage().PHP_EOL;
}
I recommend doing some research on this subject, there are a lot of patterns, and everyone has different opinions.
I'm a new with OOP model in PHP. I has been trying to retrieve data from database but something related to private makes me stuck.
This is my code.
<?php
require ("UserData.php");
class Database{
public function getUser($sql){
include ("includes/connect.php");
$statement = $conn->prepare ($sql);
$statement->execute();
while ($row = $statement->fetch()) {
$dataSet[] = new UserData($row);
}
if (!empty($dataSet)) {
return $dataSet;
}else{
die();
}
}
}
?>
the second file
<?php
class UserData
{
private $user_id, $phone,$name,$address;
public function _construct($dbrow){
$this->user_id = $dbrow['user_id'];
$this->name = $dbrow['name'];
$this->phone = $dbrow['phone'];
$this->address = $dbrow['address'];
}
public function getUserId(){
return $this->user_id;
}
public function getUserName(){
return $this->name;
}
public function getUserPhone(){
return $this->phone;
}
public function getUserAddress(){
return $this->address;
}
}
?>
and the last one
<?php require ("Database.php"); ?>
<html>
<head>
<title>OOP</title>
</head>
<body>
<?php
include("includes/connect.php");
$db = new Database();
$dataSet = $db -> getUser ("SELECT * from user");
if ($dataSet) {
foreach ($dataSet as $data) {
echo "<p>";
echo "ID" .$data->getUserId()."<br />";
echo "Name" .$data->getUserName()."<br />";
echo "Phone" .$data->getUserPhone()."<br />";
echo "Address" .$data->getUserAddress()."<br />";
echo "</p>";
}
}else{
echo "no result found";
}
?>
</body>
</html>
Well, I tried to var_dump the dataSet but the error shows up.
array(2) { [0]=> object(UserData)#5 (4) {
["user_id":"UserData":private]=> NULL ["phone":"UserData":private]=>
NULL ["name":"UserData":private]=> NULL
["address":"UserData":private]=> NULL } [1]=> object(UserData)#6 (4) {
["user_id":"UserData":private]=> NULL ["phone":"UserData":private]=>
NULL ["name":"UserData":private]=> NULL
["address":"UserData":private]=> NULL } }
So can anyone show me which spots make the code dump?
Everything is okay except this line,
public function _construct($dbrow){ ...
^^^^^^^^^^ it should be double underscore, not single
Your constructor method in UserData class is wrong. It should be,
public function __construct($dbrow){ ...
In PHP 5.6.0+, you can use the magic mathod __debugInfo()
class UserData
{
public function __debugInfo() {
return ['user_id' => $this->user_id, 'phone' => $this->phone, 'name' => $this->name, 'address' => $this->address];
}
}
or makes variables public, which is not intend when you have methods like getUserId
or create method to dump like:
class UserData
{
public function dump() {
var_dump($this);
}
}
btw in class Database method getUser you include all the time when method is called, quick fix: use require_once instead of include, better will be to call include/require/require_once outside of class
I'm using php static function to create instance for SESSION.
Issue is, while creating an instance of an object is created on every time when data is insertion.
So i cant add more than one data.
If its more than one, then the existing data is removed[New Object Created.]
MY CODE:
private static $session;
public static function startSession(array $config = array())
{
if (self::$session == null) {
self::$session = new lShopSession();
self::$session = self::$session->getSession();
}
dd(self::$session);
return self::$session;
}
function test()
{
$lshop = self::startSession();
$lshop->set('name', 'xxxx');
$lshop = self::startSession();
$lshop->set('name2', 'yyyy');
dd(self::startSession());
}
MY OUTPUT:
[
'name2' => 'yyyy'
]
But the first one is removed.
Any solution for this issue...?
Maybe it's not an answer, but I can't format this code properly in the comments, sry.
I don't actually know what happens in your lShopSession class and in dd() function, but here is simple example, that works (I tried to make this code more simplified and as much closer to original as I can) :
of course it's not a production code, here is one-connection test, without actual session detection
<?php
class TestSession {
public $data;
// here is no code that restore session for user
public function set($key, $val) {
$this->data[$key] = $val;
}
}
class TestManager {
private static $session = null;
public static function startSession() {
if (is_null(self::$session)) {
self::$session = new TestSession;
}
return self::$session;
}
public function test() {
$l = self::startSession();
$l->set('name', 'val');
$l = self::startSession();
$l->set('name2', 'val2');
var_dump(self::startSession());
}
}
$a = new TestManager;
$a->test();
results:
class Session#2 (1) {
public $data =>
array(2) {
'name' =>
string(3) "val"
'name2' =>
string(4) "val2"
}
}
I am working on a small PHP website which is based on MVC. I have a front controller (front.php) which loads the controller (services.php), runs the action method (hostingAction()) and includes the html (view.phtml). There is a method call in view.phtml ($this->renderContent()) that includes the inner content (hosting.phtml).
QUESTION:
How can I set properties (e.g. $title = 'My Title';) in the hostingAction() method and then in view.phtml do <title><?php echo $title ?></title>?
Zend Framework does something like $this->view->title = 'My Title'; in the controller and then in the view does something like <title><?php echo $view->title; ?></title>.
Currently I am overloading the properties. I am managing to set the properties in the controller action but failing to access them in my view. What am I doing wrong here?
SAMPLE CODE:
front.php
class front {
private $view;
function __construct() {
$this->view = new viewProperties();
$this->constructController();
include('application/views/view.phtml');
}
private function constructController() {
$c = new services();
$this->doAction($c);
}
public function renderContent() {
include('application/views/services/hosting.php');
}
private function doAction($c) {
$c->hostingAction();
}
}
services.php
class services {
public function hostingAction() {
$this->view->page_title = 'Services - Hosting';
$this->view->banner_src = '/assets/images/banners/home_02.jpg';
$this->view->banner_title = 'reload';
}
}
viewProperties.php
class viewProperties {
private $data = array ();
public function __set($name, $value) {
$this->data[$name] = $value;
}
public function __get($name) {
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
}
}
view.phtml
<html>
<head>
<title><?php echo $this->view->page_title; ?></title>
</head>
<body>
<?php $this->renderContent() ?>
</body>
</html>
hosting.phtml
<div id="banner">
<img src="<?php echo $this->view->banner_src ?>" alt="<?php echo $this->view->banner_title ?>" />
</div>
Your Services object does not have access to $view.
Try these mods:
front.php (with setter)
class front {
private function constructController() {
$c = new services();
$c->setView($this->view);
$this->doAction($c);
}
}
services.php (with setter)
class services {
private $view;
public function setView(viewProperties $view) {
$this->view = $view;
}
public function hostingAction() {
$this->view->page_title = 'Services - Hosting';
$this->view->banner_src = '/assets/images/banners/home_02.jpg';
$this->view->banner_title = 'reload';
}
}
Using a Singleton
Also, you could make viewProperties a singleton (per your comments):
viewProperties (with singleton)
class viewProperties {
private $instance = null;
private function __construct() {}
public static function getInstance() {
if (null === $this->instance) {
$this->instance = new self();
}
return $this->view;
}
}
front (with singleton)
class front {
private $view;
function __construct() {
$this->view = viewProperties::getInstance();
$this->constructController();
include('application/views/view.phtml');
}
}
services.php (with singleton)
class services {
private $view;
function __construct() {
$view = viewProperties::getInstance();
}
public function hostingAction() {
$this->view->page_title = 'Services - Hosting';
$this->view->banner_src = '/assets/images/banners/home_02.jpg';
$this->view->banner_title = 'reload';
}
}
Using Multi-dimensional Variables
Finally, in regards to you using 'banner_src' and 'banner_title', You can use the method I mentioned in your original post, which scales better.
NOTE The example below was copied from my reply to your original post, and has not been fixed to match your new code. It is showing that you can store arrays() for multidimensional data and shows how to access them from your view.
class services extends controller {
public function indexAction() {
$this->view->banner = array
(
'src' => '/path/to/images/banners/home_02.jpg',
'alt' => 'banner title'
);
}
public function hostingAction() {
$this->view->banner = array
(
'src' => '/path/to/images/banners/home_02.jpg',
'alt' => 'banner title'
);
}
}
<img src="<?php echo $this->view->banner['src'] ?>" alt="<?php echo $this->view->banner['title'] ?>" />
Are there any libraries to protect against CSRF(PHP5.1/5.2) or do I need to create on myself? I use this snippet from Chris, but without a library I am getting a lot of duplication on every page.
I found this library for PHP5.3, but I am wondering if there are any on PHP5.1/5.2 because I don't believe yet all hosting support PHP5.3.
Since I use Kohana - I've just extended couple of its core classes. It can be used in any code with a little changes though:
class Form extends Kohana_Form
{
public static function open($action = NULL, array $attributes = null)
{
if (is_null($action))
{
$action = Request::current()->uri . ($_SERVER['QUERY_STRING'] ? '?' . $_SERVER['QUERY_STRING'] : '');
}
$open = parent::open($action, $attributes);
$open .= parent::hidden(self::csrf_token_field(), self::csrf_token());
return $open;
}
public static function csrf_token_field()
{
return 'csrf_token';
}
public static function csrf_token()
{
$session = Session::instance();
$token = $session->get(self::csrf_token_field());
if (!$token)
{
$session->set(self::csrf_token_field(), $token = md5(uniqid()));
}
return $token;
}
}
class Validate extends Kohana_Validate
{
public function __construct(array $array, $csrf = true)
{
parent::__construct($array);
if ($csrf)
$this->add_csrf();
}
public static function factory(array $array, $csrf = true)
{
return new Validate($array, $csrf);
}
private function add_csrf()
{
$this->rules(form::csrf_token_field(), array(
'not_empty' => array(),
'csrf' => array()
));
}
protected function csrf($token)
{
return $token == form::csrf_token();
}
}