1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
13:
14: 15: 16: 17: 18: 19:
20: class PdoSessionHandler implements \SessionHandlerInterface
21: {
22: 23: 24:
25: private $pdo;
26:
27: 28: 29:
30: private $dbOptions;
31:
32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45:
46: public function __construct(\PDO $pdo, array $dbOptions = array())
47: {
48: if (!array_key_exists('db_table', $dbOptions)) {
49: throw new \InvalidArgumentException('You must provide the "db_table" option for a PdoSessionStorage.');
50: }
51:
52: $this->pdo = $pdo;
53: $this->dbOptions = array_merge(array(
54: 'db_id_col' => 'sess_id',
55: 'db_data_col' => 'sess_data',
56: 'db_time_col' => 'sess_time',
57: ), $dbOptions);
58: }
59:
60: 61: 62:
63: public function open($path, $name)
64: {
65: return true;
66: }
67:
68: 69: 70:
71: public function close()
72: {
73: return true;
74: }
75:
76: 77: 78:
79: public function destroy($id)
80: {
81:
82: $dbTable = $this->dbOptions['db_table'];
83: $dbIdCol = $this->dbOptions['db_id_col'];
84:
85:
86: $sql = "DELETE FROM $dbTable WHERE $dbIdCol = :id";
87:
88: try {
89: $stmt = $this->pdo->prepare($sql);
90: $stmt->bindParam(':id', $id, \PDO::PARAM_STR);
91: $stmt->execute();
92: } catch (\PDOException $e) {
93: throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
94: }
95:
96: return true;
97: }
98:
99: 100: 101:
102: public function gc($lifetime)
103: {
104:
105: $dbTable = $this->dbOptions['db_table'];
106: $dbTimeCol = $this->dbOptions['db_time_col'];
107:
108:
109: $sql = "DELETE FROM $dbTable WHERE $dbTimeCol < :time";
110:
111: try {
112: $stmt = $this->pdo->prepare($sql);
113: $stmt->bindValue(':time', time() - $lifetime, \PDO::PARAM_INT);
114: $stmt->execute();
115: } catch (\PDOException $e) {
116: throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
117: }
118:
119: return true;
120: }
121:
122: 123: 124:
125: public function read($id)
126: {
127:
128: $dbTable = $this->dbOptions['db_table'];
129: $dbDataCol = $this->dbOptions['db_data_col'];
130: $dbIdCol = $this->dbOptions['db_id_col'];
131:
132: try {
133: $sql = "SELECT $dbDataCol FROM $dbTable WHERE $dbIdCol = :id";
134:
135: $stmt = $this->pdo->prepare($sql);
136: $stmt->bindParam(':id', $id, \PDO::PARAM_STR);
137:
138: $stmt->execute();
139:
140:
141: $sessionRows = $stmt->fetchAll(\PDO::FETCH_NUM);
142:
143: if (count($sessionRows) == 1) {
144: return base64_decode($sessionRows[0][0]);
145: }
146:
147:
148: $this->createNewSession($id);
149:
150: return '';
151: } catch (\PDOException $e) {
152: throw new \RuntimeException(sprintf('PDOException was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e);
153: }
154: }
155:
156: 157: 158:
159: public function write($id, $data)
160: {
161:
162: $dbTable = $this->dbOptions['db_table'];
163: $dbDataCol = $this->dbOptions['db_data_col'];
164: $dbIdCol = $this->dbOptions['db_id_col'];
165: $dbTimeCol = $this->dbOptions['db_time_col'];
166:
167:
168: $encoded = base64_encode($data);
169:
170: try {
171: $driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
172:
173: if ('mysql' === $driver) {
174:
175:
176:
177: $stmt = $this->pdo->prepare(
178: "INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time) " .
179: "ON DUPLICATE KEY UPDATE $dbDataCol = VALUES($dbDataCol), $dbTimeCol = VALUES($dbTimeCol)"
180: );
181: $stmt->bindParam(':id', $id, \PDO::PARAM_STR);
182: $stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
183: $stmt->bindValue(':time', time(), \PDO::PARAM_INT);
184: $stmt->execute();
185: } elseif ('oci' === $driver) {
186: $stmt = $this->pdo->prepare("MERGE INTO $dbTable USING DUAL ON($dbIdCol = :id) ".
187: "WHEN NOT MATCHED THEN INSERT ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, sysdate) " .
188: "WHEN MATCHED THEN UPDATE SET $dbDataCol = :data WHERE $dbIdCol = :id");
189:
190: $stmt->bindParam(':id', $id, \PDO::PARAM_STR);
191: $stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
192: $stmt->execute();
193: } else {
194: $stmt = $this->pdo->prepare("UPDATE $dbTable SET $dbDataCol = :data, $dbTimeCol = :time WHERE $dbIdCol = :id");
195: $stmt->bindParam(':id', $id, \PDO::PARAM_STR);
196: $stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
197: $stmt->bindValue(':time', time(), \PDO::PARAM_INT);
198: $stmt->execute();
199:
200: if (!$stmt->rowCount()) {
201:
202:
203: $this->createNewSession($id, $data);
204: }
205: }
206: } catch (\PDOException $e) {
207: throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
208: }
209:
210: return true;
211: }
212:
213: 214: 215: 216: 217: 218: 219: 220:
221: private function createNewSession($id, $data = '')
222: {
223:
224: $dbTable = $this->dbOptions['db_table'];
225: $dbDataCol = $this->dbOptions['db_data_col'];
226: $dbIdCol = $this->dbOptions['db_id_col'];
227: $dbTimeCol = $this->dbOptions['db_time_col'];
228:
229: $sql = "INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time)";
230:
231:
232: $encoded = base64_encode($data);
233: $stmt = $this->pdo->prepare($sql);
234: $stmt->bindParam(':id', $id, \PDO::PARAM_STR);
235: $stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
236: $stmt->bindValue(':time', time(), \PDO::PARAM_INT);
237: $stmt->execute();
238:
239: return true;
240: }
241: }
242: