Introduction to Classes
Session is a characteristic in internet programming languages to keep up the state of a logged-in person.
Prerequisite for Understanding Classes
One should know 3 tier structure to grasp the session. If somebody hasn’t heard about this then to explain briefly, the three tier structure consists of a consumer machine (mainly browser), internet server and database. A dynamic internet utility consists of three tier structure.
Browser communicates with an online server to get dynamically generated HTML content material with the assistance of a database.
Classes come into image for sustaining communication between browser and internet server.
To know the working of the session we can be utilizing PHP for this text. For sensible functions one can set up an XAMPP utility accessible at no cost on the web.
Fundamentals of session
Net purposes use HTTP/HTTPS protocol for interplay between Browser and the online server and these protocols are stateless. Stateless signifies that the server and browser doesnt keep the state of the connection for recurring requests. For each request the TCP connection is established between browser and the online server. The dynamically generated HTML content material is delivered and the TCP connection is closed.
Session is a characteristic in internet purposes that maintains the state of a logged-in person between concurrent requests between browsers and the online utility server.
Cookies play an essential function on the consumer aspect for sustaining classes. Cookies are saved on browsers finish that are bonded with respective domains. The cookie identify, values pair are connected/despatched as part of headers with each request to the area internet server for each request from the browser.
Going the PHP Means
Let’s begin with a easy Hi there world within the index.php file.
<?php
echo ‘Hi there World’;
?>
When executed by way of browser the output is as beneath.
On examine component we will see the brand new display screen as beneath.
Once I examine the browser we will see comparable headers for index.php as beneath.
This easy inspection can be required that can assist you perceive the circulate of the session. After we consult with headers it’s to search for particulars as talked about within the above display screen.
session_start()
The operate used to deal with classes in PHP is session_start() on the server finish.
How does session_start() work?
Let’s perceive this with an instance.
<?php
session_start();
echo ‘Hi there World’;
?>
O/P – Hi there World
The O/P could be very anticipated. However within the background there are a lot of checks occurring.
When a request is made to the server from the browser the operate session_start() checks for a cookie with identify PHPSESSID. If this cookie doesn’t exist then the operate makes certain to create one within the browser by way of the headers within the HTML response. The worth of the cookie PHPSESSID is an alphanumeric string. This string worth is prepended with a default worth (“sess_” set in php.ini) for use because the identify of the file to be created within the momentary folder on the server. Such recordsdata are created for each person the place respective person SESSION knowledge is saved.
Headers on first entry:
Request
GET /rnd/index.php HTTP/1.1
Settle for: textual content/html,utility/xhtml+xml,utility/xml;q=0.9,*/*;q=0.8
Improve-Insecure-Requests: 1
Host: localhost:8080
Consumer-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Model/15.3 Safari/605.1.15
Settle for-Language: en-GB,en;q=0.9
Settle for-Encoding: gzip, deflate
Connection: keep-alive
Response
HTTP/1.1 200 OK
Set-Cookie: PHPSESSID=pct9tjl6imbuepdl4scp513962; path=/
Pragma: no-cache
Content material-Sort: textual content/html; charset=UTF-8
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Date: Solar, 13 Mar 2022 09:29:05 GMT
Cache-Management: no-store, no-cache, must-revalidate
Preserve-Alive: timeout=5, max=100
Content material-Size: 11
Connection: Preserve-Alive
Server: Apache/2.4.52 (Unix) PHP/8.1.3
X-Powered-By: PHP/8.1.3
On each subsequent request to the server, the browser incorporates this cookie with identify PHPSESSID, which is consumed by the server to open the respective session file whose identify could be manipulated by way of the worth of the cookie PHPSESSID for learn/write operation. Each person has a singular cookie worth generated by the web site. This helps in uniquely figuring out the person. This elementary helps the server to establish a request of the person and keep away from collusion with different customers session knowledge.
Headers for Second / Subsequent request:
Request
GET /rnd/index.php HTTP/1.1
Cookie: PHPSESSID=pct9tjl6imbuepdl4scp513962
Settle for: textual content/html,utility/xhtml+xml,utility/xml;q=0.9,*/*;q=0.8
Improve-Insecure-Requests: 1
Host: localhost:8080
Consumer-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Model/15.3 Safari/605.1.15
Settle for-Language: en-GB,en;q=0.9
Settle for-Encoding: gzip, deflate
Connection: keep-alive
Response
HTTP/1.1 200 OK
Pragma: no-cache
Content material-Sort: textual content/html; charset=UTF-8
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Management: no-store, no-cache, must-revalidate
Date: Solar, 13 Mar 2022 09:06:06 GMT
Preserve-Alive: timeout=5, max=100
Content material-Size: 11
Connection: Preserve-Alive
X-Powered-By: PHP/8.1.3
Server: Apache/2.4.52 (Unix) PHP/8.1.3
That is how cookies help sustaining the classes between browser and the online server.
Allow us to see what occurs on the server finish once we attempt to create session particular knowledge.
<?php
$userID = 1;
$firstName = ‘Ramesh’;
session_start();
$_SESSION[id] = $userID;
$_SESSION[‘name’] = $firstName;
echo ‘Hi there World’;
?>
First we have to discover the trail the place session recordsdata are created. For this we are able to use the beneath shell command.
$ php -r ‘echo “PHP Classes PATH: “.((session_save_path()) ? session_save_path():sys_get_temp_dir() ).PHP_EOL;’
PHP Classes PATH: /var/folders/2g/2hsh1sjx2_v2gkrp6_s_3_4r0000gn/T
$
$ cd /var/folders/2g/2hsh1sjx2_v2gkrp6_s_3_4r0000gn/T
$ ls -l
..
drwx—— 3 ramesh employees 96 Mar 14 17:49 homed
drwx—— 2 ramesh employees 64 Mar 14 17:49 icdd
drwx—— 3 ramesh employees 96 Mar 14 18:09 itunescloudd
drwx—— 2 ramesh employees 64 Mar 14 19:25 metrickitd
$
On executing the above code this generates a session file on this folder.
$ ls -l
..
drwx—— 3 ramesh employees 96 Mar 14 17:49 homed
drwx—— 2 ramesh employees 64 Mar 14 17:49 icdd
drwx—— 3 ramesh employees 96 Mar 14 18:09 itunescloudd
drwx—— 2 ramesh employees 64 Mar 14 19:25 metrickitd
drwx—— 2 ramesh employees 24 Mar 14 21:59 sess_pct9tjl6imbuepdl4scp513962
$
So, the file is created. Allow us to verify the content material of the file.
$ cat sess_pct9tjl6imbuepdl4scp513962
id|i:1;identify|s:6:”Ramesh”
One can simply see the session file content material as id|i:1;identify|s:6:”Ramesh”
The important thing / worth pair in $_SESSION is serialized the PHP method and saved in a session file.
So, we are able to use the session_start() operate as beneath for login.
<?php
$username = $_POST[‘username’];
$password = $_POST[‘password’];
$userdetails = getUserDetails($username);
if(isValidPassword($userdetails[‘password’], $password)) {
session_start();
$_SESSION[‘user_id’] = $userdetails[‘user_id’];
$_SESSION[‘username’] = $userdetails[‘username’];
$_SESSION[‘firstname’] = $userdetails[‘firstname’];
header(‘Location: dashboard.php’);
}
?>
From the above fundamentals one have to be clear that session knowledge is saved on the server within the respective person file which could be opened by way of the session id supplied as part of cookie by the browser.
Since, the session knowledge is saved in recordsdata for every person session. There’s a risk {that a} web site has many customers actively on-line and lots of session recordsdata respectively.
Testing the session dealing with with Apache Benchmark
Apache Benchmark (ab) is a instrument for benchmarking your server utility. It’s designed to offer you an impression of how your present internet utility performs. This particularly reveals you what number of requests per second your internet utility is able to serving.
So, we’ll attempt to set off a load of 1,000 concurrent requests per sec on the internet utility to see what occurs regarding the session.
This load will attempt to create 1,000 session recordsdata on the server and in the end result in depletion of inodes required for creation of recordsdata and your internet utility stops responding.
Inodes assist the system set up knowledge. Though inodes do not retailer the precise content material of the file, they maintain the areas of the varied chunks for each file, together with different metadata, together with: The dimensions of the file. Numerous storage gadgets and areas the place recordsdata are saved.
The creation of a file on a storage media depends on the inodes availability. If inodes get exhausted no extra recordsdata could be created.
To beat this example one can change to a different mode of saving session knowledge. For this PHP gives a operate session_set_save_handler() to customise the best way the session ought to work.
This operate takes 9 operate names as arguments so as as beneath.
operate open(string $savePath, string $sessionName) : bool {}
operate shut(): bool {}
operate learn(string $sessionId): string {}
operate write(string $sessionId, string $knowledge): bool {}
operate destroy(string $sessionId): bool {}
operate gc(int $lifetime): bool {}
operate create_sid(): string {} //non-compulsory
operate validate_sid(string $key): bool {} //non-compulsory
operate update_timestamp(string $key, string $val): bool {} //non-compulsory
Instance:
<?php
session_set_save_handler(
‘open’,
‘shut’,
‘learn’,
‘write’,
‘destroy’,
‘garbageCollector’,
‘createSessionID’,//non-compulsory
‘validateSessionID’,//non-compulsory
‘updateTimestamp’//non-compulsory
);
?>
As you may see the operate takes 9 string values of which 3 are non-compulsory. These strings are the identify of the operate dealing with respective performance.
To reveal the circulate of session we’ll attempt with creating every operate and inserting an echo assertion for the operate identify with __FUNCTION__ as beneath
<?php
ini_set(‘session.use_strict_mode’,true);
operate open($sessionPath, $sessionName): bool
{
echo ‘<br/>’.__FUNCTION__;
return true;
}
operate shut(): bool
{
echo ‘<br/>’.__FUNCTION__;
return true;
}
operate learn($sessionID): string
{
echo ‘<br/>’.__FUNCTION__;
Return ”;
}
operate write($sessionID, $sessionData): bool
{
echo ‘<br/>’.__FUNCTION__;
return true;
}
operate destroy($sessionID): bool
{
echo ‘<br/>’.__FUNCTION__;
return true;
}
operate garbageCollector($varSessionMaxlifetime): bool
{
echo ‘<br/>’.__FUNCTION__;
return true;
}
operate createSessionID(): string
{
echo ‘<br/>’.__FUNCTION__;
return uniqid(”, true);
}
operate validateSessionID($sessionID): bool
{
echo ‘<br/>’.__FUNCTION__;
return true;
}
operate updateTimestamp($sessionID, $sessionData): bool
{
echo ‘<br/>’.__FUNCTION__;
return true;
}
session_set_save_handler(
‘open’,
‘shut’,
‘learn’,
‘write’,
‘destroy’,
‘garbageCollector’,
‘createSessionID’,//non-compulsory
‘validateSessionID’,//non-compulsory
‘updateTimestamp’//non-compulsory
);
session_start();
echo ‘<br/>Hi there World’;
?>
On executing above PHP code we’ll observe the totally different order wherein the provided operate executes for first and concurrent requests.
O/P Under when above code executed first time.
open
createSessionID
learn
Hi there World
write
shut
O/P Under for concurrent execution.
open
validateSessionID
learn
Hi there World
write
shut
session_set_save_handler:
Session Storage
Until now we had been refering to storing the session knowledge within the filesystem. There are different modes we are able to help to retailer session knowledge like databases.
As we all know to alter the mode of saving knowledge we are able to use the session_set_save_handler() operate. By customizing we are able to enhance the session dealing with capability of the online utility.
Right here one can use MySQL as a database for demonstrating this.
Let’s begin with making a desk session in phpSession database as beneath.
//Database phpSession
CREATE TABLE IF NOT EXISTS `classes` (
`sessionID` CHAR(32) NOT NULL,
`sessionLastAccessTimestamp` INT UNSIGNED NOT NULL,
`sessionData` TEXT,
PRIMARY KEY (`sessionID`)
) ENGINE=InnoDB;
As everyone knows, knowledge saved in a desk corresponds to saving knowledge to the corresponding desk file for MySQL database. The information for every person can be differentiated within the type of rows for every person. Since we’re utilizing a single desk for all customers, all customers session knowledge can be saved in a single single file, So, no worries for inodes depletion.
Let’s begin with coding as beneath.
File: db_session.php
<?php
outline(‘DB_HOSTNAME’, ‘localhost’);
outline(‘DB_USERNAME’, ‘username’);
outline(‘DB_PASSWORD’, ‘password’);
outline(‘DB_DATABASE’, ‘phpSession’);
$db = mysqli_connect(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
operate open($sessionPath, $sessionName): bool
{
return true;
}
operate shut(): bool
{
GLOBAL $db;
$db = null;
return true;
}
operate learn($sessionID): string
{
GLOBAL $db;
$sessionData = ”;
$varCurrentTimestamp = time();
$sql = “
SELECT
`sessionData`
FROM
`classes`
WHERE
`sessionID` = ‘$sessionID‘;”;
$end result = mysqli_query($db, $sql);
if (mysqli_num_rows($end result) === 0) {
$sql = “
INSERT INTO
`classes`
SET
`sessionID` = ‘$sessionID‘,
`sessionLastAccessTimestamp` = $varCurrentTimestamp;”;
mysqli_query($db, $sql);
}
return $sessionData;
}
operate write($sessionID, $sessionData): bool
{
GLOBAL $db;
$sql = “
UPDATE
`classes`
SET
`sessionData` = ‘$sessionData‘
WHERE
`sessionID` = ‘$sessionID‘;”;
mysqli_query($db, $sql);
return true;
}
operate destroy($sessionID): bool
{
GLOBAL $db;
$sql = “
DELETE FROM
`classes`
WHERE
`sessionID` = ‘$sessionID‘;”;
mysqli_query($db, $sql);
return true;
}
operate garbageCollector($varSessionMaxlifetime): bool
{
GLOBAL $db;
$varCurrentTimestamp = time();
$sql = “
DELETE FROM
`classes`
WHERE
`sessionLastAccessTimestamp` + $varSessionMaxlifetime < $varCurrentTimestamp;”;
mysqli_query($db, $sql);
return true;
}
operate createSessionID(): string
{
return uniqid(”, true);
}
operate validateSessionID($sessionID): bool
{
GLOBAL $db;
$varCurrentTimestamp = time();
$sql = “
SELECT
`sessionID`
FROM
`classes`
WHERE
`sessionID` = ‘$sessionID‘;”;
$end result = mysqli_query($db, $sql);
return (mysqli_num_rows($end result) === 0) ? false : true;
}
operate updateTimestamp($sessionID, $sessionData): bool
{
GLOBAL $db;
$varCurrentTimestamp = time();
$sql = “
UPDATE
`classes`
SET
`sessionLastAccessTimestamp` = $varCurrentTimestamp
WHERE
`sessionID` = ‘$sessionID‘;”;
mysqli_query($db, $sql);
return true;
}
?>
The params to session_set_save_handler() operate are mainly names of those created features in respective order.
<?php
session_set_save_handler(
‘open’,
‘shut’,
‘learn’,
‘write’,
‘destroy’,
‘garbageCollector’,
‘createSessionID’,//non-compulsory
‘validateSessionID’,//non-compulsory
‘updateTimestamp’//non-compulsory
);
session_start();
echo ‘<br/>Hi there World’;
?>
After you have set the habits features as per above you can begin with utilizing classes as you had been whereas programming. Relating to $sessionData how it’s serialized, the main points on serialization strategies could be discovered right here on official PHP web site.
<?php
require_once ‘db_session.php’;
$username = $_POST[‘username’];
$password = $_POST[‘password’];
$userdetails = getUserDetails($username);
if(isValidPassword($userdetails[‘password’], $password)) {
session_start();
$_SESSION[‘user_id’] = $userdetails[‘user_id’];
$_SESSION[‘username’] = $userdetails[‘username’];
$_SESSION[‘firstname’] = $userdetails[‘firstname’];
header(‘Location: dashboard.php’);
}
?>
One can change the code as per their database preferences. Like if somebody desires to make use of a NoSql database like Redis or different databases then they should change the code as per their requirement.
There may be another approach to change the mode of saving knowledge, and that’s to alter the worth of param session.save_handler within the php.ini file. The worth to this variable defines the identify of the handler with which the session must be dealt with for storing and retrieving session knowledge. [Defaults to files.]
By default session.save_handler helps recordsdata, sqlite, redis, memcached. Amongst these recordsdata is the default worth.
session.save_handler = recordsdata
To help different instruments one can use session_set_save_handler(). This may override the habits set by way of session.save_handler setting in php.ini.
The most important distinction between working of session by way of session.save_handler in php.ini and session_set_save_handler() operate is session.save_handler has predefined habits/logic for managing the session; the place as by way of session_set_save_handler() one can customise the habits as required.
To elucidate what it means with predefined habits, lets assume session.save_handler = recordsdata. Right here classes implement locking habits for an online request.
What does locking imply in session?
Allow us to assume a person requests a restricted internet web page content material which requires a session. The web page content material masses and triggers a number of ajax calls instantly and the response HTML content material is loaded contained in the browser.
Since there are a number of requests coming to the server from the identical person the cookie with identify PHPSESSID has the identical worth for all of the requests, it will level to the identical session file (whereas saving session knowledge in recordsdata) for accessing session knowledge concurrently. The session file is accessed as soon as per every request. The primary request to entry the session file locks it for its use and different requests have to attend until the lock is launched. The lock is launched when the PHP script execution will get accomplished and is then accessible for others. So your ajax requests are served in sequential method as per the supply of the session file for I/O operation.
That is the default habits of session.save_handler and to override this locking habits one can use session_set_save_handler().
As we’ve got seen, within the implementation of session_set_save_handler() for MySQL, On Comparable analogy, one can verify the locking habits of a file by way of executing beneath script with a number of internet requests.
File: file_session_rnd.php
<?php
$startTimestamp = time();
session_start();
sleep(10);
$endTimestamp = time();
$timeTakenByScript = ($endTimestamp – $startTimestamp);
echo ‘Time taken by script=”.$timeTakenByScript. ” seconds’;
?>
Execute the identical script in a number of browser tabs. Anticipated end result for each the tabs is “Time taken by script = 10 seconds”. However the first executed tab will inform the time taken is 10 seconds whereas the second tab will inform a determine greater than 10 seconds.
The purpose to notice is we’re saving the timestamp at first of the script earlier than beginning the session after which sleeping for 10 seconds after beginning the session. As soon as the session file lock is launched by tab1 execution, that is then accessible for the following request. Until that point the session file lock is launched; tab2 script waits and we see a rise within the execution time.
Lets see how we are able to unlock this locking habits of file primarily based classes by way of session_set_save_handler() operate.
File: custom_file_session.php
<?php
operate open($sessionPath, $sessionName): bool
{
return true;
}
operate shut(): bool
{
return true;
}
operate learn($sessionID): string
{
$sessionData = ”;
$tempFolder = sys_get_temp_dir();
$sessionFile = “{$tempFolder}/{$sessionID}“;
if(file_exists($sessionFile)) {
$sessionData = file_get_contents($sessionFile);
}
return $sessionData;
}
operate write($sessionID, $sessionData): bool
{
$tempFolder = sys_get_temp_dir();
$sessionFile = “{$tempFolder}/{$sessionID}“;
return file_put_contents($sessionFile,$sessionData);
}
operate destroy($sessionID): bool
{
$tempFolder = sys_get_temp_dir();
$sessionFile = “{$tempFolder}/{$sessionID}“;
return unlink($sessionFile);
}
operate garbageCollector($varSessionMaxlifetime): bool
{
return true;
}
operate createSessionID($varSessionMaxlifetime): string
{
return uniqid(”, true);
}
operate validateSessionID($sessionID): bool
{
$tempFolder = sys_get_temp_dir();
$sessionFile = “{$tempFolder}/{$sessionID}“;
return file_exists($sessionFile);
}
operate updateTimestamp($sessionID, $sessionData): bool
{
$tempFolder = sys_get_temp_dir();
$sessionFile = “{$tempFolder}/{$sessionID}“;
return contact($sessionFile);
}
session_set_save_handler(
‘open’,
‘shut’,
‘learn’,
‘write’,
‘destroy’,
‘garbageCollector’,
‘createSessionID’,//non-compulsory
‘validateSessionID’,//non-compulsory
‘updateTimestamp’//non-compulsory
);
$startTimestamp = time();
session_start();
sleep(10);
$endTimestamp = time();
$timeTakenByScript = ($endTimestamp – $startTimestamp);
echo ‘Time taken by script=”.$timeTakenByScript. ” seconds’;
?>
Within the above code each param operate isn’t depending on a worldwide file pointer. As an alternative the file operations are executed throughout the respective operate itself. This implies learn and write operations could be carried out on a single file on the similar second. No lock for session recordsdata so ajax name execution dont want to attend for earlier request to get accomplished for accessing the session file.
So, if you’re considering that switching the habits from session.save_handler to session_set_save_handler() will enhance the efficiency; the reply is NO. There are few precautions to be taken care of.
When ought to one take away locking from a session?
Session is used to avoid wasting knowledge in $_SESSION which could be accessed throughout requests till the important thing/knowledge worth is eliminated.
If there’s locking the information set in $_SESSION for earlier request X can be accessible for subsequent request Y. It is because the session knowledge studying and writing operations are in sequential method for every request till all of the requests are served.
Opposite, if you take away locking it’s potential that the session knowledge learn/write operation is carried out on the similar second. This will likely result in knowledge loss. For e.g, requests X, Y are triggered on the similar time by a logged-in person. These will attempt to carry out learn/write operations concurrently. However when request X provides a key/worth pair in $_SESSION which is able to get saved as soon as executed with the execution. The request X extra key/worth knowledge receivedt be accessible in request Y. As a result of the time after they each accessed the information for $_SESSION, was the identical for each. However the saving of the information could happen at totally different timestamps. Suppose, request Y doesn’t make any adjustments to key/worth pairs in $_SESSION and the request takes some extra time than request X to get accomplished. The request X which had adjustments are written to vacation spot which can then get replaced by request Y $_SESSION knowledge which was the unique knowledge. So, this will result in lack of knowledge.
It is advisable to watch out with this if you find yourself not utilizing a session with out locking habits.
The thumb rule to make use of classes with out locking is to avoid wasting knowledge in session solely on the time of login and never from wherever within the internet utility. If there’s a requirement for transferring one knowledge to the redirected URL, then you need to use the GET technique to switch one time knowledge throughout requests or redirects.
Why ought to one go for classes with out locks?
As a result of classes are meant for sustaining login particulars and never for including / deleting knowledge that are used throughout requests. In case you want knowledge throughout requests use the GET technique as talked about.
The benefit of utilizing session with out lock is, the session knowledge can be set solely as soon as when the person login and henceforth requests don’t have any write operations to be carried out on session. This manner concurrent requests have uniform $_SESSION knowledge.
With out locks classes can take the efficiency of internet purposes to a subsequent stage. Since there’s solely learn operation for the session knowledge for all requests after login,
PHP gives a characteristic the place script solely reads the session knowledge and closes the session instantly after loading the information into $_SESSION regardless of the requests are but to finish its execution.
This may be achieved by passing params to the session_start() operate supporting this characteristic as beneath.
<?php
session_start([
‘read_and_close’ => true,
]);
?>
So, we are able to say for session_set_save_handler
<?php
session_set_save_handler(
‘open’,
‘shut’,
‘learn’,
‘write’,
‘destroy’,
‘garbageCollector’,
‘createSessionID’,//non-compulsory
‘validateSessionID’,//non-compulsory
‘updateTimestamp’//non-compulsory
);
session_start([
‘read_and_close’ => true,
]);
echo ‘<br/>Hi there World’;
?>
If we verify the output of session operate names by way of above code, its as beneath.
O/P for session features sequence:
open
validateSessionID
learn
shut
Hi there World
From above one can be taught that the session is learn and closed in a single assertion itself.
session_start([
‘read_and_close’ => true,
]);
This masses the session knowledge and instantaneously closes it making the script accessible with $_SESSION. There may be an opportunity that in a selected request you might wish to carry out the write operation within the session. For this we are able to begin the session as regular and do required operations.
<?php
session_start([
‘read_and_close’ => true,
]);
echo ‘<br/>Hi there World 1’;
session_start();
echo ‘<br/>Hi there World 2’;
?>
O/P for session features sequence:
open
validateSessionID
learn
shut
Hi there World 1
open
validateSessionID
learn
Hi there World 2