Singleton Pattern In PHP.... How Can I Save State Between Requests - php

With the use of static variables and the singleton pattern, I thought that it would be easy enough to create a simple shopping cart that remembered what items where in the cart when another page was loaded.
I am having a problem of the shopping cart not remembering what was already in it when the page is refreshed.
Is there a problem with my code below or should I just use globals or a mysql database.
What is the best way to go about storing state..
<?php
//create a singleton class
class shoppingCart {
private static $_shoppingCartItems = array();
private static $_instance = null;
private function __construct(){
}
public static function getInstance(){
if(self::$_instance == null)
self::$_instance = new shoppingCart();
return self::$_instance;
}
public function add(ShoppingItem $item){
$this->_shoppingCartItems[] = $item;
}
public function cartCount(){
return count($this->_shoppingCartItems);
}
}
?>
Implementation
$item = new shoppingItem();
$shoppingCart = shoppingCart::getInstance();
$shoppingCart->add($item);
$shoppingCart->add($item);
//should increment by 2 on each page load but it doesn't
echo $shoppingCart->cartCount();

Static class members (or any other variables for that matter) are not preserved across different requests. Never.
Sessions to the rescue
The only exception to this is $_SESSION; which is a special mechanism to allow for just that.
Star the session with session_start() at the top of your script.
You can now use $_SESSION like a regular array to store and retrieve information. A session belongs to a single user, it is not a means of sharing data across all your users.
Have a look here for an introduction.
Silence
You must not output anything before session_start() is called. That is to say, <?php must be the exact first thing in a PHP script that wishes to use sessions. Further, there must be no echo statements or any other output generating functions between <?php and session_start().
Output Buffering
If you really must generate output before starting the session, you can use output buffering.
Notes
$_SESSION is forgetful. After a certain time of inactivity on the user's side, the data will be deleted.
If you get the following error message, you violated the above guidelines. Another possibility is that your script has a BOM (Unicode byte order mark). If so, remove it.
Warning: session_start(): Cannot send session cookie - headers already
sent by (output started at
The reason this happens is due to the way PHP handles output: It tries to get the output as fast as possible to the user. However, the HTTP protocol transmits certain control data (cookies, which session belongs to you etc), called "headers" before all the output ("body") of the response. As soon as you output anything, the headers need to get sent - unless you use output buffering that is.

I think I can see your thought pattern there but what you're trying to do is wrong in many ways.
1. Singleton is NOT a pattern, it's an antipattern
The Singleton is an anti-pattern and should be avoided at all costs. See this great answer by Gordon for the why.
2. HTTP is a stateless protocol.
Nothing you do in PHP alone will help you to preserve state across two requests. Your $shoppingCart is created from the scratch for each request, in fact, your whole application is. You should NOT try to persist data in objects instead you should recreate state after every request, by fetching the respective data from somewhere else. In your example probably from some sort of database nosql or sql.
3. Sessions
You can persist user specific data in the superglobal $_SESSION, but in most cases I advice against it. Your user session should hold authentication and user data but you should avoid storing all kinds data relevant for your business logic in there.

PHP is not an application server. It will not automatically persist your "application" state between requests. You have to do that yourself via $_SESSION, cookies, and/or your own private methods.
Unless you take steps to preserve data, the state of the application is wiped when the HTTP request that invoked the script(s) is ended.

Related

A class property gets cleared at the end of a method execution

I have a structure like this:
class My_Class extends Another_Class {
private $my_data = array();
public function append_to_my_data() {
$my_data[] = $this->get_result();
}
}
The append_to_my_data method is called from an AJAX recursion, it is supposed to handle an array by small pieces and combine results by appending them to the $my_data property. But it seems that on each call of this method, the $my_data property is empty again and does not contain the results from the previous call.
Why does it happen? Should I look for another method of storing this data? I would not like to store the data in my JavaScript recursion because it might be quite deep and the data might get quite large.
By AJAX, I assume you mean Javascript.
This tells me one thing, you try to persist data between http requests from your client app (the Javascript code) and your server app code (PHP).
Be aware the JS/client runs on the user's machine in the browser, and the PHP code runs on your own server machine. Two totaly different machines with separate memory/hard disk and CPU.
To persist data on the server between different http requests there are many ways/approaches you can use.
The two MOST common ways are to use php sessions and/or MySQL database, there are many more ways to do it, the two above are the most common ones.
And, to access an object property, you will need to use the $this
i.e.:
$this->my_data[] = $this->get_result();
and not
$my_data[] = $this->get_result();

Cannot expire cookie from a controller in CakePHP 2.x

I am building an API in CakePHP. I have a function that as part of its execution first destroys the cookies associated with the session. I am using the following code to do this.
public function new_thing () {
// I first call another controller to use functions from that controller
App::import('Controller', 'Person');
$PersonsController = new PersonsController;
// This function call is the problem
// This does not throw any errors but does not destroy the cookie as requested
$PersonsController->_kill_auth_cookie()
}
// This is from the Person controller, these are the functions used in the API
// This is the function that sets the cookies
public function _set_auth_cookie( $email ) {
setcookie(Configure::read('auth_cookie_name'), $email);
}
// this is the function that does not properly destroy the cookie from the API
// interestingly, it does work when called from in this controller
public function _kill_auth_cookie() {
setcookie(Configure::read('auth_cookie_name'), 'xxx', time()-7200);
}
I cannot get the API to properly expire the cookie that is created earlier in the session, I am not sure why. Additionally—what is maddening—is that the logs are empty and no error is being thrown of any kind, so I am not sure what to do next.
There is so much wrong in this code and concept…
DON'T instantiate controllers anywhere. It is plain wrong, broken by design and violates the MVC pattern. Only one controller should be dispatched by the framework itself based on the request; you don’t instantiate them manually.
An API using cookies? Well, not impossible but definitely not nice to work with. It’s possible but I’ve never seen one in the wild. I feel sorry for the person who has to implement it. See this question.
Why are you not using the CookieComponent? It has a built-in destroy() method to remove a cookie.
If you have an “auth” cookie, why are you not using CakePHP’s built-in Auth system? It will deal with all of that.
Use App::uses() not App::import() here
By convention, only protected functions should be prefixed with _
The first point is very likely the reason why cookie and sessions are messed up because the second controller instance initiates components again, and by this cookie and session maybe a second time as well. However, this can lead to “interesting” side effects.
I first call another controller to use functions from that controller
This is the evidence that your architecture is broken by design. The code that needs to be executed somewhere else; should be in a model method in this case. Or at least a component if there are controller-related things to be shared between different controllers.

PHP: custom session handler

just a small question regarding the php session handler,
let's say i want to store the session in a database because i have multiple servers that should have access to the session, i would write my own sessionhandler using the interface as described in http://php.net/manual/en/class.sessionhandler.php,
but how can i use it?
if i do
session_set_save_handler(....);
session_start();
$_SESSION['key'] = 'value';
will it save the data using my handler?
The class that you define and set in set_save_handler() should have all the functions required in the lifetime of a session to be defined. These include read(), write(), destroy() among others.
Once that is defined correctly you can still manipulate sessions the normal way you do, but in the background, the functions you define will get executed based on which session event you are performing.
For e.g. $_SESSION['key'] = 'value' will perform the write() function (in which you might have coded a database save routine)
You can read more about it at: http://us3.php.net/manual/en/function.session-set-save-handler.php

Is using superglobals directly good or bad in PHP?

So, I don't come from a huge PHP background—and I was wondering if in well formed code, one should use the 'superglobals' directly, e.g. in the middle of some function say $_SESSION['x'] = 'y'; or if, like I'd normally do with variables, it's better to send them as arguments that can be used from there, e.g:
class Doer {
private $sess;
public function __construct(&$sess) {
$this->sess =& $sess;
}
}
$doer = new Doer($_SESSION);
and then use the Doer->sess version from within Doer and such. (The advantage of this method is that it makes clear that Doer uses $_SESSION.)
What's the accepted PHP design approach for this problem?
I do like to wrap $_SESSION, $_POST, $_GET, and $_COOKIE into OOP structures.
I use this method to centralize code that handles sanitation and validation, all of the necessary isset () checks, nonces, setcookie parameters, etc. It also allows client code to be more readable (and gives me the illusion that it's more maintainable).
It may be difficult to enforce use of this kind of structure, especially if there are multiple coders. With $_GET, $_POST, and $_COOKIE (I believe), your initialization code can copy the data, then destroy the superglobal. Maybe a clever destructor could make this possible with $_SESSION (wipe $_SESSION on load, write it back in the destructor), though I haven't tried.
I don't usually use any of these enforcement techniques, though. After getting used to it, seeing $_SESSION in code outside the session class just looks strange, and I mostly work solo.
EDIT
Here's some sample client code, in case it helps somebody. I'm sure looking at any of the major frameworks would give you better ideas...
$post = Post::load ();
$post->numeric ('member_age');
$post->email ('member_email');
$post->match ('/regex/','member_field');
$post->required ('member_first_name','member_email');
$post->inSet ('member_status',array('unemployed','retired','part-time','full-time'));
$post->money ('member_salary');
$post->register ('member_last_name'); // no specific requirements, but we want access
if ($post->isValid())
{
// do good stuff
$firstName = $post->member_first_name;
}
else
{
// do error stuff
}
Post and its friends all derive from a base class that implements the core validation code, adding their own specific functionality like form tokens, session cookie configuration, whatever.
Internally, the class holds a collection of valid data that's extracted from $_POST as the validation methods are called, then returns them as properties using a magic __get method. Failed fields can't be accessed this way. My validation methods (except required) don't fail on empty fields, and many of them use func_get_args to allow them to operate on multiple fields at once. Some of the methods (like money) automatically translate the data into custom value types.
In the error case, I have a way to transform the data into a format that can be saved in the session and used to pre-populate the form and highlight errors after redirecting to the original form.
One way to improve on this would be to store the validation info in a Form class that's used to render the form and power client-side validation, as well as cleaning the data after submission.
Modifying the contents of the superglobals is considered poor practice. While there's nothing really wrong with it, especially if the code is 100% under your control, it can lead to unexpected side effects, especially when you consider mixed-source code. For instance, if you do something like this:
$_POST['someval'] = mysql_real_escape_string($_POST['someval']);
you might expect that everywhere PHP makes that 'someval' available would also get changed, but this is not the case. The copy in $_REQUEST['someval'] will be unchanged and still the original "unsafe" version. This could lead to an unintentional injection vulnerability if you do all your escaping on $_POST, but a later library uses $_REQUEST and assumes it's been escaped already.
As such, even if you can modify them, it's best to treat the superglobals as read-only. If you have to mess with the values, maintain your own parallel copies and do whatever wrappers/access methods required to maintain that copy.
I know this question is old but I'd like to add an answer.
mario's classes to handle the inputs is awesome.
I much prefer wrapping the superglobals in some way. It can make your code MUCH easier to read and lead to better maintainability.
For example, there is some code at my current job the I hate! The session variables are used so heavily that you can't realistically change the implementation without drastically affecting the whole site.
For example,
Let's say you created a Session class specific to your application.
class Session
{
//some nice code
}
You could write something like the following
$session = new Session();
if( $session->isLoggedIn() )
{
//do some stuff
}
As opposed to this
if( $_SESSION['logged'] == true )
{
//do some stuff
}
This seems a little trivial but it's a big deal to me. Say that sometime in the future I decide that I want to change the name of the index from 'logged' to 'loggedIn'.
I now have to go to every place in the app that the session variable is used to change this. Or, I can leave it and find someway to maintain both variables.
Or what if I want to check that that user is an admin user and is logged in? I might end up checking two different variables in the session for this. But, instead I could encapsulate it into one method and shorten my code.
This helps other programmers looking at your code because it becomes easier to read and they don't have to 'think' about it as much when they look at the code. They can go to the method and see that there is only ONE way to have a logged in user. It helps you too because if you wanted to make the 'logged' in check more complex you only have to go to one place to change it instead of trying to do global finds with your IDE and trying to change it that way.
Again, this is a trivial example but depending on how you use the session this route of using methods and classes to protect access could make your life much easier to live.
I would not recommend at all passing superglobal by reference. In your class, it's unclear that what you are modifying is a session variable. Also, keep in mind that $_SESSION is available everywhere outside your class. It's so wrong from a object oriented point of view to be able to modify a variable inside a class from outside that class by modifying a variable that is not related to the class. Having public attribute is consider to be a bad practice, this is even worst.
I found my way here while researching for my new PHP framework.
Validating input is REALLY important. But still, I do often find myself falling back to code like this:
function get( $key, $default=FALSE ){
return (isset($_GET[$key]) ? $_GET[$key]:$default);
}
function post( $key, $default=FALSE ){
return (isset($_POST[$key]) ? $_POST[$key]:$default);
}
function session( $key, $default=FALSE ){
return (isset($_SESSION[$key]) ? $_SESSION[$key]:$default);
}
Which I then use like this:
$page = get('p', 'start');
$first_name = post('first_name');
$last_name = post('last_name');
$age = post('age', -1);
I have found that since I have wildly different requirements for validation for different projects, any class to handle all cases would have to be incredibly large and complex. So instead I write validation code with vanilla PHP.
This is not good use of PHP.
get $_SESSION variables directly:
$id = $_SESSION['id'];
$hash = $_SESSION['hash'];
etc.

Zend PHP Class Variable retention for mysql queries

I have a flash application which uses a single php file to retrieve records from a database (using the Zend framework). When the application first begins, I make a call to the php to set a class variable, so that all future requests to the database will use this variable to select records based on its value. So here is how the class begins:
class MyClass
{
private $animal = "";
public function setAnimal($anim) {
$this->animal = $anim;
echo($this->animal); //this correctly prints the variable I passed in
}
Later, based on user input, I make a call to a different method in this class, but it's as if the class variable $animal has been forgotten, because it no longer has a value on any subsequent accessing of the class:
public function getAnimals()
{
echo('getAnimals: ');
echo($this->animal); //this prints nothing - as if it doesn't know what "animal" is
$result = mysql_query("SELECT * FROM animals WHERE animal='$this->animal'"); //and therefore this query doesn't work
$t = array();
while($row = mysql_fetch_assoc($result))
{
array_push($t, $row);
}
return $t;
}
So my question is, how can I get a PHP class variable to persist so that I can set it once, and I can access it anytime during the life of an application?
I could be mis-interpreting your question, but it sounds like you first make a call to a PHP script from your Flash, and later you are making a second call to the PHP script from the Flash and expecting a certain variable to be set?
If this is the case, then it is also the problem. PHP is stateless. Every time you access a PHP script (ie, request the URL), the PHP environment is re-created from scratch. As soon as the request is done and the PHP script is finished executing, the environment is destroyed (ie. the web server thread shuts down, and the PHP environment is lost). Anything you set or do in your first request won't exist on your second request.
If you want information to persist, you can use sessions or cookies. Since you're using Flash, sessions is probably the best way to go. The first time you call your script, generate a session token and pass it back to the flash with your response. On all subsequent calls, your Flash should provide the session token, and you can store/fetch any state variables you need from $_SESSION.

Categories