Working with cookies and session inside PHP class - php

I have some function (pasted below little piece of function), which I used as separate function and it worked well.
Now I want to move this functon into some class. As you see, it works with $_SESSION and $_COOKIE.
Question is, is it required to send $_SESSION and $_COOKIE as input data while calling this function (I mean something like that: calling like protect($_SESSION, $_COOKIE) and then fetch them from inside function)? or it will work without sending them?
...
public function protect() {
session_start();
if (isset($_SESSION['HTTP_USER_AGENT'])) {
if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])) {
$this->logout();
exit;
}
}
if (!isset($_SESSION['id']) && !isset($_SESSION['login'])) {
if (isset($_COOKIE['id']) && isset($_COOKIE['key'])) {
...

$_COOKIE and $_SESSION are superglobals, which means they are available everywhere. You never need to import them, pass them as arguments or anything similar, they are always available in any scope.
For this reason, they should always be treated as read-only - assigning a new value to them will affect the rest of the scripts execution in every scope.

$_SESSION AND $_COOKIE are superglobals, meaning they are available in all scopes. So it is not strictly necessary to pass them as parameters to functions.
However, there is a benefit in passing them as parameters when you start unit testing. Parameters will make it considerably easier to test values to the function without needing them to be available in $_SESSION or $_COOKIE.

You dont need to pass the $_SESSION or $_COOKIE variables as they are superglobals - accessible from anywhere ... from the docs :
This is a 'superglobal', or automatic global, variable. This simply means that it is available in all scopes throughout a script. There is no need to do global $variable; to access it within functions or methods.

Related

PHP get_defined_vars() doesn't print superglobals inside function

I'm working through debugging some legacy code, and want to use a pre-built function that is essentially a wrapper for get_defined_vars().
Running this code directly in the calling file prints an array of variables as expected:
print_r(get_defined_vars());
However, wrapping this in a simplified version of my function prints an empty array:
function debugAllVars() {
print_r(get_defined_vars());
}
debugAllVars();
Regardless of the scope, I would have expected "superglobal" variables such as $_POST to be present in the output.
Why is the output completely empty?
get_defined_vars() prints all variables in the "symbol table" of the scope where it is called. When you try to wrap it as debugAllVars, you introduce a new scope, which has a new symbol table.
For a standalone function like this, the symbol table consists of:
the function's parameters
any global variables imported into the current scope using the global keyword
any static variables declared in the current scope with the static keyword (even if not assigned a value)
any variables implicitly declared by assigning a value to them
any variables implicitly declared by taking a reference to them (e.g. $foo = &$bar would implicitly declare $bar if not already defined; $foo = $bar would not)
Notably, this list does not include the superglobals, such as $_GET, $_POST, and $GLOBALS. If you run get_defined_vars() in global scope (i.e. outside any function), you will see that these are present in the symbol table there, which is also what the magic variable $GLOBALS points to. So, why are they not present in every scope, and how can we use them if they're not?
For this, we need to dig into the internals of the implementation, where these variables are referred to as "auto-globals" rather than "superglobals".
The answer to why is performance: the naive implementation of an "auto-global" would be one that acted as though every function automatically had a line at the top reading global $_GET, $_POST, ...;. However, this would mean copying all those variables into the symbol table before every function was run, even if they weren't used.
So instead, these variables are special-cased in the compiler, while converting your PHP code into the internal "opcodes" used by the VM which executes the code.
Using a source code browser, we can see how this works.
The key function is zend_is_auto_global in zend_compile.c (taken from current master, effectively PHP 7.2):
zend_bool zend_is_auto_global(zend_string *name) /* {{{ */
{
zend_auto_global *auto_global;
if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) {
if (auto_global->armed) {
auto_global->armed = auto_global->auto_global_callback(auto_global->name);
}
return 1;
}
return 0;
}
Here, name is the name of a variable, and CG means "compiler globals", so the main job of this function is to say "if the variable name given is in a compiler-global hash called auto_globals, return 1". The additional call to auto_global_callback allows the variable to be "lazy loaded", and only populated when it is first referenced.
The main usage of that function appears to be this conditional, in zend_compile_simple_var_no_cv:
if (name_node.op_type == IS_CONST &&
zend_is_auto_global(Z_STR(name_node.u.constant))) {
opline->extended_value = ZEND_FETCH_GLOBAL;
} else {
opline->extended_value = ZEND_FETCH_LOCAL;
}
In other words, if the variable name you referenced is in the list of superglobals, the compiler switches the opcode into a different mode, so that when it is executed, it looks up the variable globally rather than locally.
get_defined_vars gets all variables defined in the scope that it's called in. Your debugAllVars function introduces a new scope, so get_defined_vars will at most give you all variables within debugAllVars. It cannot give you variables from the caller's scope.
Also see Reference: What is variable scope, which variables are accessible from where and what are "undefined variable" errors?.

How can I return an $_SESSION as opposed to the value of the $_SESSION?

I ran into a small problem that was easily fixed, but got me thinking about the idea of returning a $_SESSION from a function as opposed to returning the value of the $_SESSION. As an example, let's say I want to write a function to unset a $_SESSION (I know that the following example is silly, but I'm hoping to use it to illustrate a point).
function sessionFunction($name) {
return $_SESSION[$name];
}
$session_to_unset = sessionFunction('unset_me');
unset($session_to_unset);
The above won't work because I'm returning the value of the $_SESSION as opposed to returning the $_SESSION itself.
Of course, I could just do (again...very silly function, but used to illustrate a point):
function sesssionFunction($name) {
return $name;
}
$session_to_unset = sessionFunction('unset_me');
unset($_SESSION[$name]);
but, I'm wondering if there's a way to actually return the $_SESSION array as opposed to its populated value so that I can unset the returned value (as in the first example).
There is nothing you can do that will enable the straight unset($var) syntax. That's because there is no hook in PHP that lets you customize the behavior of unset -- there's the magic method __unset, but that only comes into play when called on object properties.
$_SESSION is a "superglobal". From the documentation:
This is a 'superglobal', or automatic global, variable. This simply means that it is available in all scopes throughout a script. There is no need to do global $variable; to access it within functions or methods.
There is no need to return it, as it is available in its correct form anywhere anyway.

Is it possible to declare a variable as "always global"?

Is there any way I can define a variable such a way that I don't need to global $var1; in every function? Just define it in beginning and keep using where ever needed. I know $GLOBALS exist, but don't want to use it.
First let me try to explain why you shouldn't use globals because they are extremely hard to manage. Say a team member overrides an $ADMIN variable in a file to be 1, and then all code that references the $ADMIN variable will now have the value of 1.
globals are so PHP4, so you need to pick a better design pattern, especially if this is new code.
A way to do this without using the ugly global paradigm is to use a class container. This might be known as a "registry" to some people.
class Container {
public static $setting = "foo";
}
echo Container::$setting;
This makes it more clear where this variable is located, however it has the weakness of not being able to dynamically set properties, because in PHP you cannot do that statically.
If you don't mind creating an object, and setting dynamic variables that way, it would work.
You need to pass the variable as a parameter to that function to avoid using GLOBALS.
The Problematic Scenario (Works ! but avoid it at all costs)
<?php
$test = 1;
function test()
{
global $test;
echo $test; // <--- Prints 1
}
test();
The right way...
<?php
$test = 1;
function test($test)
{
echo $test; // <--- Prints 1
}
test($test); //<--- Pass the $test param here
This behaviour called as superglobal variable. But php has limited predefined list of them: Superglobals.
So you cannot add your own superglobal variable.
Variable scope
My suggestions from the most to less radical:
Edit source code of PHP and add your own superglobals.
Do not write code at all.
Do not use PHP (use different language with different variable scope policy).
Do not use functions (write plain script).
Use constants instead of variables.
Use function params instead of using globals.
Use static variables instead of globals. (\G::$variable)

custom super global in PHP

Is it possible to define a custom super global variable? (whether in code, or using php.ini)
Example, for all projects I use a custom framework. The framework essentially stores all data about running instance of the script (template loaded, template variables, etc.) in a single variable. I'd like that variable to become cross-system accessible.
I am perfectly aware of $_GLOBALS and global, however the question is asking if it is possible to define custom super global variable, e.g. $foo, which would become accessible by the same name in any scop.
Sadly there is no way to define superglobals.
(There is no mechanism in PHP for user-defined superglobals.)
Source
Sorry, but all answers are wrong.
Correct answer: yes, it is possible, but not with the so-called "core" PHP functionalities.
You have to install an extension called runkit:
http://www.php.net/manual/en/runkit.installation.php
After that, you can set your custom superglobals in php.ini as documented here:
http://www.php.net/manual/en/runkit.configuration.php#ini.runkit.superglobal
This is not possible, and also bad design. (as are super globals).
If you do think global state is the answer for you, you could use static classes.
I'm not offering a solution to this problem as such, but I suggest that you avoid using globals. Generally speaking use of globals is considered bad practice, even in programming languages that make use of them by design. You cannot be sure how your global will affect other applications that declare the same variable. Personally I would prefer a more managed approach to retrieving data, either specifically from another php script or by writing a php extension that defines a new function and returns the data you want. It's not unusual to store application settings in a database, be that MySQL or flat file text, and would be my preferred method for sharing information cross-application.
A little hack(trick) that can be used as superglobals, it is a singletone like implementation but I am agree with #Matt Esch, don't use superglobals ...
class K
{
public $CONST = array();
private static $_instance = null;
private function __construct()
{
}
protected function __clone()
{
}
static public function I()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
}
then you can use this in all methods, class, functions, like a superglobal var.
K::I()->CONST[0] = "somevar";
K::I()->CONST[1] = array(1, 2, 3, 4, 5);
My solution
Really php dont support to define more superglobals but if you want share vars between differents users and sessions, my solution is to create a unique session for save shared information. The proccess consist in to close current session, open the shared session to write and read and back in to the previous session.
Code:
<?php
ini_set('display_errors',1);
error_reporting(E_ALL);
function get_global($key){
//Get current session
if(session_status()!=PHP_SESSION_ACTIVE)session_start();
$current_id=session_id();
session_write_close();
//Set a global session with session_id=1
session_id(1);
session_start();
//Get superglobal value
$value=null;
if(isset($_SESSION[$key]))$value=$_SESSION[$key];
session_write_close();
//Set the before session
session_id($current_id);
session_start();
return $value;
}
function set_global($key,$value){
//Get current session
if(session_status()!=PHP_SESSION_ACTIVE)session_start();
$current_id=session_id();
session_write_close();
//Set a global session with session_id=1
session_id(1);
session_start();
//Set superglobal value
$_SESSION[$key]=$value;
session_write_close();
//Set the before session
session_id($current_id);
session_start();
}
//Example
//Begin my session normally
session_start();
if(empty($_SESSION['count'])){
$_SESSION['count']=0;
$_SESSION['color']="rgb(".rand(0,255).",".rand(0,255).",".rand(0,255).")";
}
$_SESSION['count']++;
$id=session_id();
//Get the superglobal
$test=get_global("test");
//Set the superglobal test with empty array if this dont set
if($test==null)$test=array();
//Get the superglobal
$test=get_global("test");
//Set values for each reload page and save the session_id that create it
$test[]="<span style='color:".$_SESSION['color']."'>Value: ".rand(0,100)." SessionID: $id</span><br>";
//Save the superglobal
set_global("test",$test);
//Show the superglobal
foreach($test as $t){
echo $t;
}
echo "<b>Reloads = ".$_SESSION['count'].", <span style='color:".$_SESSION['color']."'>This my color</span></b>";
exit;
?>
Test:
In this example $test is superglobal var that contain array with random number and session_id that created it. Each session defines two local variables for color text and count reloads..

Superglobals can't be accessed via variable variables in a function?

I can't access superglobals via variable variables inside a function. Am I the source of the problem or is it one of PHP's subtleties? And how to bypass it?
print_r(${'_GET'});
works fine
$g_var = '_GET';
print_r(${$g_var});
Gives me a Notice: Undefined variable: _GET
PHP isn't able to recognize that this is a global variable access:
It compiles $_GET and ${'_GET'} to the same opcode sequence, namely a global FETCH_R. ${$g_var} on the other hand will result in a local FETCH_R.
This is also mentioned in the docs:
Superglobals cannot be used as variable variables inside functions or class methods.
You can possibly bypass it using $GLOBALS superglobal variable. Instead of writing
function & getSuperGlobal($name) {
return ${"_$name"};
}
you can write
function & getSuperGlobal($name) {
return $GLOBALS["_$name"];
}
and the results will equal.
It seems that the last PHP versions are dealing fine with that problem.
Next code works fine with PHP 5.5.9.
<?php
function foo() {
print_r(${'_SERVER'});
}
foo();

Categories