1: <?php
2:
3: /*****************************************************************************************
4: * X2Engine Open Source Edition is a customer relationship management program developed by
5: * X2Engine, Inc. Copyright (C) 2011-2016 X2Engine Inc.
6: *
7: * This program is free software; you can redistribute it and/or modify it under
8: * the terms of the GNU Affero General Public License version 3 as published by the
9: * Free Software Foundation with the addition of the following permission added
10: * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11: * IN WHICH THE COPYRIGHT IS OWNED BY X2ENGINE, X2ENGINE DISCLAIMS THE WARRANTY
12: * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13: *
14: * This program is distributed in the hope that it will be useful, but WITHOUT
15: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16: * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
17: * details.
18: *
19: * You should have received a copy of the GNU Affero General Public License along with
20: * this program; if not, see http://www.gnu.org/licenses or write to the Free
21: * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22: * 02110-1301 USA.
23: *
24: * You can contact X2Engine, Inc. P.O. Box 66752, Scotts Valley,
25: * California 95067, USA. or at email address contact@x2engine.com.
26: *
27: * The interactive user interfaces in modified source and object code versions
28: * of this program must display Appropriate Legal Notices, as required under
29: * Section 5 of the GNU Affero General Public License version 3.
30: *
31: * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32: * these Appropriate Legal Notices must retain the display of the "Powered by
33: * X2Engine" logo. If the display of the logo is not reasonably feasible for
34: * technical reasons, the Appropriate Legal Notices must display the words
35: * "Powered by X2Engine".
36: *****************************************************************************************/
37:
38: class X2AuthCache extends CApplicationComponent {
39:
40: /**
41: * @var string the ID of the {@link CDbConnection} application component.
42: */
43: public $connectionID;
44:
45: /**
46: * @var string the name of the auth cache table.
47: */
48: public $tableName = 'x2_auth_cache';
49:
50: /**
51: * @var integer how often to garbage collect (delete expired values).
52: * GC is performed using an N-sided coin flip
53: */
54: public $gcProbability = 100;
55: private $_db;
56:
57: /**
58: * Initializes this application component.
59: * Trimmed down version of {@link CDbCache::init}.
60: */
61: public function init() {
62: parent::init();
63:
64: $db = $this->getDbConnection();
65: $db->setActive(true);
66:
67: // garbage collect every now and then
68: if (mt_rand(0, $this->gcProbability) === 0)
69: $this->gc();
70: }
71:
72: /**
73: * Looks up all the auth results for the specified user ID.
74: * @param integer $userId the user ID, defaults to current user
75: * @return array associative array of authItem names and boolean permission values
76: */
77: public function loadAuthCache($userId = null) {
78:
79: if ($userId === null)
80: $userId = Yii::app()->user->getId();
81: if (empty($userId))
82: return array();
83:
84: $time = time();
85: $sql =
86: 'SELECT authItem, value, params
87: FROM ' . $this->tableName . '
88: WHERE userId=' . $userId . ' AND (expire=0 OR expire>' . time() . ')
89: LIMIT 200';
90:
91: $db = $this->getDbConnection();
92: if ($db->queryCachingDuration > 0) {
93: $duration = $db->queryCachingDuration;
94: $db->queryCachingDuration = 0;
95: $rows = $db->createCommand($sql)->queryAll();
96: $db->queryCachingDuration = $duration;
97: } else
98: $rows = $db->createCommand($sql)->queryAll();
99:
100: $results = array();
101:
102: foreach ($rows as &$row) {
103: $results[$row['authItem']][$row['params']] = $row['value'];
104: }
105:
106: return $results;
107: }
108:
109: /**
110: * Retrieves a value from cache with a specified key.
111: * @param string $userId the user ID, defaults to current user
112: * @param string $authItem the authItem
113: * @return bool the cached permission value, or null if the value is not in the cache or expired.
114: */
115: // public function checkResult($userId, $authItem) {
116: // if (empty($userId))
117: // return null;
118: //
119: // $time = time();
120: // $sql = "SELECT value FROM {$this->tableName} WHERE userId=$userId AND authItem='$authItem' AND (expire=0 OR expire>$time)";
121: // $db = $this->getDbConnection();
122: // if ($db->queryCachingDuration > 0) {
123: // $duration = $db->queryCachingDuration;
124: // $db->queryCachingDuration = 0;
125: // $result = $db->createCommand($sql)->queryScalar();
126: // $db->queryCachingDuration = $duration;
127: // } else
128: // $result = $db->createCommand($sql)->queryScalar();
129: // if ($result === false)
130: // return null;
131: // else
132: // return (bool) $result;
133: // }
134:
135: /**
136: * Stores a value identified by a key into cache if the cache does not contain this key.
137: * This is the implementation of the method declared in the parent class.
138: *
139: * @param string $userId the user ID
140: * @param string $authItem the authItem
141: * @param string $value the value to be cached
142: * @return boolean true if the value is successfully stored into cache, false otherwise
143: */
144: private $_authCacheSize = null;
145: public function addResult($userId, $authItem, $value, $cacheParams = array()) {
146: $expire = time() + 259200; // expires in 3 days
147:
148: $value = $value ? '1' : '0'; // convert value to 1 or 0
149:
150: $cacheStr = json_encode($cacheParams);
151:
152: $sql = "REPLACE INTO {$this->tableName} (userId,authItem,expire,value,params) VALUES ($userId,'$authItem',$expire,$value,:cacheStr)";
153: try {
154: $command = $this->getDbConnection()->createCommand($sql)->execute(array(':cacheStr' => $cacheStr));
155: return true;
156: } catch (Exception $e) {
157: return false;
158: }
159: }
160:
161: /**
162: * @return CDbConnection the DB connection instance
163: * @throws CException if {@link connectionID} does not point to a valid application component.
164: */
165: public function getDbConnection() {
166: if ($this->_db !== null)
167: return $this->_db;
168: else if (($id = $this->connectionID) !== null) {
169: if (($this->_db = Yii::app()->getComponent($id)) instanceof CDbConnection)
170: return $this->_db;
171: else
172: throw new CException(Yii::t('yii', 'CDbCache.connectionID "{id}" is invalid. Please make sure it refers to the ID of a CDbConnection application component.', array('{id}' => $id)));
173: }
174: else {
175: $dbFile = Yii::app()->getRuntimePath() . DIRECTORY_SEPARATOR . 'cache-' . Yii::getVersion() . '.db';
176: return $this->_db = new CDbConnection('sqlite:' . $dbFile);
177: }
178: }
179:
180: /**
181: * Removes the expired data values.
182: */
183: protected function gc() {
184: $this->getDbConnection()->createCommand('DELETE FROM ' . $this->tableName . ' WHERE expire>0 AND expire<' . time())->execute();
185: }
186:
187: /**
188: * Deletes all values from cache.
189: * @return boolean whether the flush operation was successful.
190: */
191: public function clear() {
192: $this->getDbConnection()->createCommand('DELETE FROM ' . $this->tableName . '')->execute();
193: return true;
194: }
195:
196: }
197: