PHP7 breaks my sessions when using a custom session handler and seccond postgres connection is made

When using a custom session handler to save sessions on a postgreSQL server, open a postgres seccond connection and the session will break if any Unicode characters are present!

This is my custom session handler:

class custom_session_handler implements SessionHandlerInterface { protected $nombre_de_sesion, $tiempo_de_vida, $db; public function open($savePath, $sessionName) { $this->db = pg_connect("host=**** port=5432 dbname=**** user=**** password=***") or die('Imposible conectar con la base de datos de sesiones'); $this->gc(time()); $this->nombre_de_sesion = trim($sessionName); $this->tiempo_de_vida = pg_escape_literal(time() + 2500); return (isset($this->nombre_de_sesion) && strlen($this->nombre_de_sesion) > 2) ? true : false; } public function close() { return pg_close($this->db); } public function destroy($session_id) { return pg_affected_rows(pg_query($this->db, 'DELETE FROM "sesiones_soporte" WHERE session_id = ' . pg_escape_literal($session_id) . '')) ? true : false; } public function write($session_id, $session_data) { $escaped_id = pg_escape_literal($session_id); $escaped_session = pg_escape_literal(pg_escape_bytea($session_data)); if (pg_affected_rows(pg_query($this->db, 'UPDATE "sesiones_soporte" SET "session_expira" = ' . $this->tiempo_de_vida . ', "session_byte"=' . $escaped_session . ' WHERE session_id = ' . $escaped_id . ' AND session_expira > ' . (int) time())) == 1) { return true; } else { pg_query($this->db, 'INSERT INTO "sesiones_soporte" ("session_id", "session_expira", "session_byte") VALUES (' . $escaped_id . ', ' . $this->tiempo_de_vida . ', ' . $escaped_session . ' )'); return true; } return false; } public function read($session_id) { $escaped_id = pg_escape_literal($session_id); $sesion = pg_unescape_bytea(pg_fetch_result(pg_query($this->db, 'SELECT session_byte FROM "sesiones_soporte" WHERE session_id = ' . $escaped_id . ' AND session_expira > ' . (int) time() . ' LIMIT 1'), 0, 'session_byte')); !isset($sesion) ? : pg_query($this->db, 'UPDATE "sesiones_soporte" SET "session_expira" = ' . $this->tiempo_de_vida . ' WHERE session_id = ' . $escaped_id . ' AND session_expira > ' . (int) time()); return (isset($sesion) ? $sesion : false); } public function gc($maxlifetime) { return pg_affected_rows(pg_query($this->db, 'DELETE FROM "sesiones_soporte" WHERE session_expira < ' . (int) $maxlifetime)); } } 

Start our handler with our session:

 $handler = new custom_session_handler(); session_set_save_handler($handler, true); session_name('my_session'); session_start(); 

And save some data in our session:

  $_SESSION['test'] = 'Ñéíóúñ'; 

At this point you can var_dump() execute your session and it will work, you can refresh the page and it will contain session information and it will work, but stay with me on this ...

well i need to check the fridge:

 $seccond_server = pg_connect("host=#### port=#### dbname=#### user=#### password=######### or die("No bueno on db #2"); print_r($_SESSION); 

Oooh, the session data looks fine, but ... wait ... Now your session is broken!

Reload the page and you will get: PHP Warning: session_start(): Failed to decode session object. Session has been destroyed in some location at some line PHP Warning: session_start(): Failed to decode session object. Session has been destroyed in some location at some line

Reloading the page again will give you: PHP Warning: pg_fetch_result(): Unable to jump to row 0 on PostgreSQL result index something in some path:

You can reproduce comments and uncomment that seccond pg_connect and the session will work until you make this seccond pg_connect

Update:

  • I forgot to mention that the same code works flawlessly in PHP 5.6.2

  • I added this problem as a comment to the PHP bug tracking system, as I found something similar: https://bugs.php.net/bug.php?id=70584

  • I just filled out a PHP error report if someone wants to follow and / or update it: https://bugs.php.net/bug.php?id=71088

  • Client and server information:

    FIRST SERVER (session store): PostgreSQL 9.4.4 on x86_64-unknown-linux-gnu, compiled gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11), 64-bit

    SECCOND SERVER: PostgreSQL 8.4.20 on x86_64-redhat-linux-gnu, compiled GCC gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11), 64-bit

    CLIENT (php): PostgreSQL (libpq) version 9.4.4

+5
source share
1 answer

The real problem:

BYTEA escaping uses different escaping methods when it comes to postgres 9 and postgres 8, and PHP does not isolate the class level pg_ @.

The real answer is:

You need to pass the correct database reference as the first argument to pg_escape_bytea() so that it can use the correct escape method:

 pg_escape_bytea($this->db, $data); 

pg_unescape() , pg_unescape() other hand, will not use your db link as an argument.

Workaround that works (you shouldn't do this):

You can, of course, wrap the session information in base64() and then run away from it like bytea. Later you will need unescape and deploy it.

It seems that escaping methods differ in how they handle multibyte strings, and therefore the base64 string does not produce any errors.

Additional Information:

yohgaki , who was flagged with a php error, pointed out various errors in my session handler, he also published an example of a well-implemented session handler using external databases. If you are interested in the full information here: https://bugs.php.net/bug.php?id=71088

+3
source

Source: https://habr.com/ru/post/1237780/


All Articles