1: <?php
2: /**
3: * Token tracking implementation for local files.
4: *
5: * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
6: *
7: * See the enclosed file COPYING for license information (LGPL). If you
8: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
9: *
10: * @author Max Kalika <max@horde.org>
11: * @category Horde
12: * @package Token
13: */
14: class Horde_Token_File extends Horde_Token_Base
15: {
16: /* File prefix constant. */
17: const FILE_PREFIX = 'conn_';
18:
19: /**
20: * Handle for the open file descriptor.
21: *
22: * @var resource
23: */
24: protected $_fd = false;
25:
26: /**
27: * Boolean indicating whether or not we have an open file descriptor.
28: *
29: * @var boolean
30: */
31: protected $_connected = false;
32:
33: /**
34: * Constructor.
35: *
36: * @see Horde_Token_Base::__construct() for more parameters.
37: *
38: * @param array $params Optional parameters:
39: * - token_dir (string): The directory where to keep token files.
40: * DEFAULT: System temporary directory
41: */
42: public function __construct($params = array())
43: {
44: $params = array_merge(array(
45: 'token_dir' => Horde_Util::getTempDir()
46: ), $params);
47:
48: parent::__construct($params);
49: }
50:
51: /**
52: * Destructor.
53: */
54: public function __destruct()
55: {
56: $this->_disconnect(false);
57: }
58:
59: /**
60: * Delete all expired connection IDs.
61: *
62: * @throws Horde_Token_Exception
63: */
64: public function purge()
65: {
66: // Make sure we have no open file descriptors before unlinking
67: // files.
68: $this->_disconnect();
69:
70: /* Build stub file list. */
71: try {
72: $di = new DirectoryIterator($this->_params['token_dir']);
73: } catch (UnexpectedValueException $e) {
74: throw new Horde_Token_Exception('Unable to open token directory');
75: }
76:
77: /* Find expired stub files */
78: foreach ($di as $val) {
79: if ($val->isFile() &&
80: (strpos($val, self::FILE_PREFIX) === 0) &&
81: (time() - $val->getMTime() >= $this->_params['timeout']) &&
82: !@unlink($val->getPathname())) {
83: throw new Horde_Token_Exception('Unable to purge token file.');
84: }
85: }
86: }
87:
88: /**
89: * Does the token exist?
90: *
91: * @param string $tokenID Token ID.
92: *
93: * @return boolean True if the token exists.
94: * @throws Horde_Token_Exception
95: */
96: public function exists($tokenID)
97: {
98: $this->_connect();
99:
100: /* Find already used IDs. */
101: $token = base64_encode($tokenID);
102: foreach (file($this->_params['token_dir'] . '/' . self::FILE_PREFIX . $this->_encodeRemoteAddress()) as $val) {
103: if (rtrim($val) == $token) {
104: return true;
105: }
106: }
107:
108: return false;
109: }
110:
111: /**
112: * Add a token ID.
113: *
114: * @param string $tokenID Token ID to add.
115: *
116: * @throws Horde_Token_Exception
117: */
118: public function add($tokenID)
119: {
120: $this->_connect();
121:
122: /* Write the entry. */
123: $token = base64_encode($tokenID);
124: fwrite($this->_fd, $token . "\n");
125:
126: $this->_disconnect();
127: }
128:
129: /**
130: * Opens a file descriptor to a new or existing file.
131: *
132: * @throws Horde_Token_Exception
133: */
134: protected function _connect()
135: {
136: if ($this->_connected) {
137: return;
138: }
139:
140: // Open a file descriptor to the token stub file.
141: $this->_fd = @fopen($this->_params['token_dir'] . '/' . self::FILE_PREFIX . $this->_encodeRemoteAddress(), 'a');
142: if (!$this->_fd) {
143: throw new Horde_Token_Exception('Failed to open token file.');
144: }
145:
146: $this->_connected = true;
147: }
148:
149: /**
150: * Closes the file descriptor.
151: *
152: * @param boolean $error Throw exception on error?
153: *
154: * @throws Horde_Token_Exception
155: */
156: protected function _disconnect($error = true)
157: {
158: if ($this->_connected) {
159: $this->_connected = false;
160: if (!fclose($this->_fd) && $error) {
161: throw new Horde_Token_Exception('Unable to close file descriptors');
162: }
163: }
164: }
165:
166: }
167: