I have PHP files a bit like this
public_html/environment.php
public_html/task.php
phpbin/actions.php
phpbin/library.php
environment.php is included by public_html/* before any other php files are included, phpbin/* assumes everything in environment.php is already available.
It defines these two globals
$g_foo = "...";
$g_bar = "...";
task.php includes this logic
function do_stuff ()
{
require_once determine_required_file ();
...
}
In this case, determine_required_file() returns "/path/to/phpbin/actions.php"
actions.php in turn contains
require_once "/path/to/phpbin/library.php"
Finally, library.php contains
$x = $g_foo;
$y = $g_bar;
I get this error:
Undefined variable: $g_bar;
Now, $g_foo and $g_bar are strictly read-only except in environment.php, I have exhaustively grepped and verified that there are no other places which create or modify variables with these names.
I am aware that PHP globals are weird, and doing things like including files from within functions can mess up your scope. I know that I should probably use define() or some other method, yeah yeah.
My question is this (yes, I'm asking you to speculate in the absence of full code, sorry):
Why might $g_bar generate an error but not $g_foo?
I assume the in-function-inclusion is probably responsible, but assuming these globals really are read-only, what should I be looking for as the culprit for why one ends up in global scope in library.php but not the other?
You need to use include_once instead of required_once for your fields that needed your global variables, or define a global $g_bar, $g_foo.
http://php.net/manual/en/language.variables.scope.php
i am having a little problems when storing objects in session. According what i think i understood, if the class is serializable and you include it before calling session_start(), php automatically serializes/unserializes the object.
In the next example (using qcodo 0.4.22 framework) i can not recover the value of the object:
require(dirname(__FILE__) . '/../includes/prepend.inc.php');
QApplication::QcodoInfo();
if (!isset($_SESSION["person"])) {
$person = Person::LoadById(1);
$_SESSION["person"]=$person;
}
else {
echo "Hello ".$_SESSION["person"]->FirstName;
}
So, in order to work i am forced to do:
require(dirname(__FILE__) . '/../includes/prepend.inc.php');
QApplication::QcodoInfo();
if (!isset($_SESSION["person"])) {
$person = Person::LoadById(1);
$_SESSION["person"]=serialize($person);
}
else {
echo "Hello ".unserialize($_SESSION["person"])->FirstName;
}
With no-qcodo classes i dont need to use serialization.
Is it possible to avoid the serialization?
Thanks for providing the link to the forums. You put a very important information in there:
When the object is in the session i get the error: “The script tried to execute a method or access a property of an incomplete object.”
That means, at the time of unserializing the session, the class definitions are not already loaded. The unserialization is done at session_start. So first load all class definitions and then start the session. Helpful in that context are:
Autoloading Classes Docs
Define unserialize_callback_func (a PHP setting, see unserializeDocs). Everytime an undefined class should be instantiated, it'll be called, so you can load the classes via a callback, like with Autloading (Autoloading comes first, you can use this one for debugging however).
Related: (The title of the question is misleading, the interesting part is the answer:) Why is unserialize_callback_func needed when spl_autoload_register is already used?
So try to find out in which like the session gets started. Maybe you only need to start it later, the PHP manual has more information about sessions in general and how to configure when it starts, there is an option to auto-start sessions, maybe you're running into that, but that's just an assumption, there is more to configure and I'm not fluent how Qcodo loads classes.
PHP Session Runtime Configuration Docs
Session Introduction Docs
Thanks!. I am closer to the solution with your comment.
Looking into qcodo core i see the place where session is initialized..... and it is done before including the classes.
The problem is that the class is included in the moment i make a call on it (how can is that possible?). I have written an echo sentence in the class file, and that echo appears in the moment where i use the class. For this, i dont know when to call session_start() in order to fix the problem.
EDIT: i have discovered the "autoload" feature in php. Is for that no?. So my question is if it is possible to keep the autoload and start the session in the right moment
EDIT2: i found finally the solution. In qcodo forums suggested me several options. Finally i had to include the data classes before qcodo calls the session_start function. Thx to everyone
I have an index.php file that has 3 includes
<?php
require_once('mod.php');
$mod = new Mod();
require_once('start.php');
require_once('tools.php');
....some code....
?>
I need to be able to reference the $mod object inside the start.php and tools.php.
How do I pass that object to be referenced by those 2 other require files?
Basically the mod.php is a class that has an array list generated in its __construct(). I want to use that array list data inside the startup.php and tools.php file but not sure how to pass in the existing one without calling "new" inside both of those files separately which doesn't do what I need since it resets everything.
Thanks!
It looks like you're using require() calls not for dynamic functionality loading (get a class definition in), but as something like a function call. Don't. Avoid global variables like a plague.
Side note: Instead of worrying about doing the require() calls in the right order to get your classes defined, I'd encourage you to look at Autoload functionality in PHP 5. It allows you to define which classes are defined in which file, and load those files on-demand when the classes are requested.
First of all use some autoloader. Dozens of require on the top of the file are annoying and needless.
You don't have to pass any references to other files. require works like "copy-paste-execute" so $mod will be available in that file.
#index.php
$mod = new Mod();
include 'file.php';
#file.php
$mod->doSth(); // works file!
Your problem is probably variable scope. If you need to use $mod inside another object (the fact that its source (class) is in another file doesn't matter) pass reference to $mod as a constructor argument, pass it using a special setter ($obj->setMod($mod); $obj->doSth();) or use more complex but better solution like Dependency Injection Container (sample implementation).
Doing require (or require_once, include, or include_once), simply includes and evaluates the code. The variable scope is inherited from the point at which the code is imported.
As an example, using your code:
<?php // index.php
require_once('mod.php');
$mod = new Mod();
require_once('start.php');
And the include:
<?php // start.php
$mod->arrayList(); // $mod is the object created in index.php
The mod should be available in those other files...if you need it in a function or class, use the global keyword, like:
function test() {
global $mod;
print $mod->list;
}
I'm new to OOP and am writing one of my first classes. I work for an insurance broker and am trying to use a Class to store things about a quote, and store the Object as a session variable.
Thing is, when I view the session variables, I get:
sessionName
__PHP_Incomplete_Class Object
(
[__PHP_Incomplete_Class_Name] => myClass
[brokerId] =>
Can anyone tell me why it's showing incomplete class name?
Make sure that either the class definition is present before session_start() is called, e.g.
require_once 'class.MyClass.php';
session_start();
or set an unserialize_callback_func that will try to load the class definition as described at http://docs.php.net/function.unserialize.
edit: this can also be done via spl_autoload_register(). E.g.
spl_autoload_register(function($name) {
// only a demo ...this might be insecure ;-)
require_once 'class.'.$name.'.php';
});
session_start();
echo '<pre>';
var_dump($_SESSION);
echo '</pre>';
I managed to fix it all by myself, not sure how though.
I ensured that the page displaying the values was structured like:
require_once("Class.php");
session_start();
$_SESSION['myObject']->printVariables();
And that the page constructing the object was like:
# Include the class
require_once($_SERVER['DOCUMENT_ROOT'] . "/Class.php");
# Instantiate a new policy
$_SESSION['myObject'] = new quote('54');
$_SESSION['myObject']->printVariables();
I also made sure that the page displaying calling the object did not use any serialize functions, as they seemed to only cause errors.
I am using this
if (!is_object($_SESSION)) $_SESSION = new ArrayObject();
I've got a site setup that, on page load, turns all user submitted strings into SafeString objects. For those unfamiliar with SafeString, it basically forces the user to echo out sanitized data preventing XSS and whatnot..
Anyways, there's a problem. My $_SESSION array is being filled with __PHP_Incomplete_Class Object. From what I've read, this is due to not initializing the class before the session and then storing class objects in the session.
Here's my code:
require_once __WEBROOT__ . '/includes/safestring.class.php';
$temp = array
(
&$_SERVER, &$_GET, &$_POST, &$_COOKIE,
&$_SESSION, &$_ENV, &$_REQUEST, &$_FILES,
&$HTTP_SERVER_VARS, &$HTTP_GET_VARS,
&$HTTP_POST_VARS, &$HTTP_COOKIE_VARS,
&$HTTP_POST_FILES, &$HTTP_ENV_VARS
);
function StringsToSafeString(&$array)
{
foreach ($array as $key => $value)
{
if (is_string($array[$key]))
{
$array[$key] = new SafeString($value);
}
if (is_array($array[$key]))
{
StringsToSafeString($array[$key]);
}
}
}
StringsToSafeString($temp);
unset($temp);
I can't think of a way to rewrite this which would solve the problem :/
Any ideas?
When you're accessing $_SESSION, you're not just changing the current script's copy of the data read from the session, you're writing SafeString objects back into the active session.
But putting custom objects in the session is dodgy and something I would generally try to avoid. To be able to do it you have to have defined the class in question before calling session_start; if you don't, PHP's session handler won't know how to deserialise the instances of that class, and you'll end up with the __PHP_Incomplete_Class Object.
So avoid frobbing the session. If you must take this approach, make a copy of the data from $_SESSION into a local $mysession array. However, I have to say I think the whole idea of a SafeString is dangerous and unworkable; I don't think this approach is ever going to be watertight. Whether a string of raw text is ‘safe’ is nothing to do with where it came from, it is a property of how you encode it for the target context.
If you get another text string from a different source such as the database, or a file, or calculated within the script itself, it needs exactly the same handling as a string that came from the user: it needs to be htmlspecialcharsed. You're going to have to write that escape anyway; the safestring gains you nothing. If you need to send the string to a different destination format, you would need a different escape.
You cannot encapsulate all string processing problems into one handy box and never think about them again; that's just not how strings work.
I know it's been years since this was asked, but I'm posting my answer because none of the answers above actually explain to the OP what is actually wrong.
PHP serializes its sessions using the built-in serialize and unserialize methods. serialize of PHP has the ability to serialize PHP objects (aka class instances) and convert them to string. When you unserialize those strings, It converts them back those same classes with those values. Classes who have some private properties and want to encode/decode that or do something complex in their serialization/deserialization implement the Serializable class and add serialize and unserialize methods to the class.
When PHP's unserialize tries to unserialize a class object, but the class name isn't declared/required, instead of giving a warning or throwing an Exception, it converts it to an object of __PHP_Incomplete_Class.
If you don't want your session objects to convert to __PHP_Incomplete_Class, You can do it by either requiring the class files before you invoke session_start, or by registering an autoload function.
You just have to include the safestring.class.php before you call session_start() when you want to read the SafeString objects from $_SESSION variable:
<?php
require_once __WEBROOT__ . '/includes/safestring.class.php';
session_start();
print_r($_SESSION);
and yeah, if you are using PHP framework that (most probably) calls session_start() internally, make sure you require_once the class file beforehand (use hooks or whatever mechanisms that the framework provides).
I solved the problem using json_encode and json_decode function.
This is where I wanted to assign the value to session.
$user_json = json_encode($user);
$_SESSION['user'] = $user_json;
This is where I show the user after decoding the json
session_start();
$user_json= $_SESSION['user'];
$user = json_decode($user_json);
This solves my problem but I am not sure about performance or security. I haven't checked them.
Lukman's answer is correct. But you already mention that in your question, so apparently you can't instantiate the class before the session starts, for some reason.
You may want to check if sessions start automatically in the php config:
http://www.php.net/manual/en/session.configuration.php#ini.session.auto-start
If they are and yu cant help that, you may want to check if you can have your classes autoloaded prior to that:
http://php.net/manual/en/language.oop5.autoload.php
If all else fails, you can still serialize the objects before you store them in a session, and unserialize them each them you retrieve them:
http://php.net/manual/en/function.serialize.php
I dont see in your code where you store your variables, but it would be something like
$mystuff = unserialize($_SESSION["mystuff"]);
$mystuff->dostuff();
$_SESSION["mystuff"] = serialize($mystuff);
Be sure to load the class definition before you unserialize your variables
$2c,
*-pike
I just dealt with something like this. Took me hours to finally find how my order was screwed.
I had a file being called asynchronously.
myFile.php
that file contained the following..
$result = include ("myOtherFile.php");
return $result;
Myotherfile.php has something like this
require_once "lib/myClassLibs.php";
require_once "webconfig.php";
the webconfig.php had the session_start() call in it.
The lib/myClassLibs has all the class info init. If you check before the webconfig call, you can see that the class is available.
If you check before the webconfig call, you will also see that the session has started already. If you check before the lib/myClassLibs.php, you will see the session is already started.
Checking in myFile.php before you include MyOtherFile.php, you find the session has not started.
This represented legacy code that has worked for the last 8 years without me fiddling with it. I pulled the includes out of the "MyOtherFile.php". Now my sessions are synching properly.
I solved this problem by including the __autoload function at the top of my php file. So it looks like this:
<?php
require_once("path/to/include.inc");
//Needed for serialization/deserialization
function __autoload($class_name) {
include "path/to/". $class_name . '.php';
}
In PHP 5, this function isn't be needed but I was stuck until I used this function. Hope this helps someone else!
I know this is a really old question but I ran into this problem. After more research and experimenting I came up with a what I think is an acceptable alternative to storing classes in the session. It might be a bit hackish, but works for my current project.
NOTE: this work-around works for me because I start a session when a user logs in and don't want to include every possible class the user might, or might not encounter during the session. Including all the classes doesn't seem practical or efficient (but maybe this isn't any better ???).
First, my base class contains the following code that populates the object attributes from a given array, automatically.
class BaseClass {
public function __construct($properties=[]){
if (!empty($properties)) {
array_walk($properties, function ($val, $key) {
$this->fromArray($key, $val);
});
}
}
public function fromArray($property, $value){
return (property_exists($this, $property)) ? $this->$property = $value : null;
}
public function toArray(){
return get_object_vars($this);
}
}
The Work-Around:
I use the toArray() method to convert a class instance to an array before it goes into the session, then create a new instance of the class when fetching it from the session.
$_SESSION['user'] = $userInstance->toArray();
// ... do stuff ...
$userInstance = new User($_SESSION['user']);
This is also really handy for writing classes to a database and converting to JSON. Both of which are made easier when working with a PHP array.
Like I said above, this may or may not be the most efficient way to handle this problem. It also raises the question, "should I be using PHP classes if I'm just going to convert to arrays?"
I run into the same problem and the solution was inspired by #bobince answer
To be able to do it you have to have defined the class in question before calling
session_start
First, my session was set like this:
$_SESSION["customer"] = $customerObj;
Then before calling the session_start(), I have to load or defined the class first by importing it and then call session_start() right after
require 'entity/Customer.php';
ob_start();
session_start();
$customer = new Customer();
if (isset($_SESSION["customer"]))
{
$customer = $_SESSION["customer"];
echo $customer->getCustomerName();
}
My mistake was sending the user to a PHP page without including the class in that page, only in the original page.
Looked something like this:
index.php
include __DIR__.'AirInfo.php';
session_start();
$plan = new Plan();
header('Location: session.php');
session.php
// Should have put include __DIR__.'AirInfo.php' here
session_start();
My mistake here was that I had set the session.auto_start setting to on. The session would then be initialized before any line of code (including the autoloader) will be called.
I have the same problem with Google Photo API When Try to Authenticate my app and Access Photo API.
Solve it by just use session_start() after include and all use statements.
Here my complete code:
include "./vendor/autoload.php";
use Google\Auth\Credentials\UserRefreshCredentials;
use Google\Photos\Library\V1\PhotosLibraryClient;
use Google\Photos\Library\V1\PhotosLibraryResourceFactory;
use Google\Auth\OAuth2;
session_start();
//rest of code comes here
Short version of #bobince's excellent answer, if you're using an MVC framework and a classmap or psr-4 autoloading etc...
[front controller]
//Do this before session start because session has an object that will not work
// if the class has not been loaded already
require_once('vendor/autoload.php');
//Start a session after your autoload
session_start();
You might just be calling,
session_start();
session_start();
twice in your code. Call it once. Check required php classes for repeats. This was the fix for me.