Helpful Information
 
 
Category: Post a PHP snippet
PostGres Sessions Class

<?php

class post_sessions {

/*SQL
Use this to create the sessions table

CREATE TABLE __tablename__ (
sess_id VARCHAR(40) PRIMARY KEY,
sess_ip VARCHAR(32) NOT NULL,
sess_time INT NOT NULL DEFAULT 0,
sess_birth INT NOT NULL DEFAULT 0,
sess_value TEXT NOT NULL
);

*/

private $sess_limit;
private $table;
private $conn;
function __construct($table, $sess_limit = 300) {
$this->sess_limit = $sess_limit;
$this->table = $table;
}

function __destruct() {
session_write_close();
}

private function encode_ip($ip) {
$ip = explode('.', $ip);
return md5(sprintf('%x%x%x%x', $ip[0], $ip[1], $ip[2], $ip[3]));
}

private function get_ip() {
if (getenv('HTTP_CLIENT_IP')) {
$this->ip = $this->encode_ip(getenv('HTTP_CLIENT_IP'));
} elseif (getenv('HTTP_X_FORWARDED_FOR')) {
$this->ip = $this->encode_ip(getenv('HTTP_X_FORWARDED_FOR'));
} elseif (getenv('REMOTE_ADDR')) {
$this->ip = $this->encode_ip(getenv('REMOTE_ADDR'));
} else {
$this->ip = $this->encode_ip('UNKNOWN'));
}
}

public function _connect($db, $host='localhost', $port=false, $user=false, $pass=false)
{
$conn_string = sprintf("%s%s%s%s%s",
($host == false ? "host=localhost" : "host=$host"),
($port == false ? "" : " port=$port"),
($db == false ? "" : " dbname=$db"),
($user == false ? "" : " user=$user"),
($pass == false ? "" : " password=$pass"));
);
$this->conn = pg_connect("$conn_string") or die('Could not connect to the database.');
return $this->conn;
}

public function _open($path, $name) {
return $this->conn;
}

public function _close() {
$this->_gc(0);
return true;
}

public function _read($sess_id) {
if ($results = pg_query($this->conn, 'SELECT sess_value FROM ' . $this->table . ' WHERE sess_id = \'' . $sess_id . '\' AND sess_ip = \'' . $this->ip . '\'') === false) {
return '';
}
if(pg_num_rows($results) > 0) {
$row = pg_fetch_object($results);
return $row->sess_value;
}
return '';
}

public function _write($sess_id, $sess_data) {
$sess_data = pg_escape_string($sess_data);
$results = pg_query($this->conn, 'UPDATE ' . $this->table . ' SET sess_time = ' . time() . ', sess_data = \'' . $sess_data . '\' WHERE sess_id = \'' . $sess_id . '\' AND sess_ip = \'' . $this->ip . '\'');
return (bool) $result;
}

$results = pg_query($this->conn, 'INSERT INTO ' . $this->table . ' (sess_id, sessip, sess_time, sess_birth, sess_value) VALUES (' . $sess_id . ', '. $this->ip . ', ' . time() .', ' . time() . ', ' . $sess_data . ');');
return (bool) $result;
}

public function _destroy($sess_id) {
$results = pg_query($this->conn, 'DELETE FROM ' . $this->table . ' WHERE sess_id = \'' . $sess_id . '\' AND sess_ip = \'' . $this->ip . '\';');
return (bool) $result;
}

public function _gc($life) {
$results = pg_query($this->conn, 'DELETE FROM ' . $this->table . ' WHERE sess_time < ' . $life . ';');
return (bool) $result;
}

}

?>

Then for a small example:



<?php
require_once 'post_sessions.class.php';
require_once 'connect.php';

$session = new post_sessions('sessions', 600);
session_set_save_handler (array(&$session, '_open'),
array(&$session, '_close'),
array(&$session, '_read'),
array(&$session, '_write'),
array(&$session, '_destroy'),
array(&$session, '_gc'));

session_start();

if(isset($_SESSION['counter'])) {
$_SESSION['counter']++;
}

else {
$_SESSION['counter'] = 1;
}

echo 'You have visted ' . $_SESSION['counter'] . 'page(s)!';
?>

Are you sure you've tested this?

Just by looking at it, I see the following problems:

1) I haven't found the PG_* constants, which you use in __costruct(), in the documentation, so I think they are user-defined. Thus I would suggest making them class constants

2) _open() uses the property "post", which is nowhere defined (or I'm just blind).

3) Instead of using:


if($abc === false)
return false;
else
return true;
you could simply do:
return $abc;
// or if you want to invert it
return (!$abc);
4) _read() may return ' ' (note the space). Is this behavior desired or should it return an empty string? The documentation says that the read function should return an empty string, if there's nothing to read (and that's the case here, imho).

5) The SQL in _read() is messed up, too. There are two single quotes, which should be escaped, but aren't.

6) In _write() $results is sometimes misspelled as $reults or $reulsts.

7) I think the insert query in _write() is never reached (if you fix the misspellings noted as #6).

8) Is it necessary that the sess_id column is 255 chararcters long? I thought that a session id would always be an 40-hexadecimal-character string.

dumpfi

I was in the process of uploading when I caught the time. I should have waited to test it, thanks for pointing out the errors though.

As for the constants, there is the slim possibility that the user won't always be using the same connection, so I'd rather leave that up to them to define. However, I'll replace them with a connection function.

As it stands right now, PHP seems to be pick and choosing which files it parses (which is really stating to make me mad) and I can't test it. I'll bring this up with the server admin and sort this out. As for now, use at your own disgression, though it SHOULD be safe and fixed now.

Also, just a general comment, but it would be great to provide a short description of the purpose of the script when posting. For people who have no idea what PostGres is in this case for example, that'd be most helpful.










privacy (GDPR)