diff --git a/lib/Data/GoogleCloudStorage.php b/lib/Data/GoogleCloudStorage.php index 2521957b..75bb8a65 100644 --- a/lib/Data/GoogleCloudStorage.php +++ b/lib/Data/GoogleCloudStorage.php @@ -2,6 +2,7 @@ namespace PrivateBin\Data; +use DateTime; use Exception; use Google\Cloud\Core\Exception\NotFoundException; use Google\Cloud\Storage\StorageClient; @@ -9,6 +10,8 @@ use PrivateBin\Json; class GoogleCloudStorage extends AbstractData { + const DATETIME_FORMAT = 'Y-m-d\TH:i:s.u\Z'; + /** * returns a Google Cloud Storage data backend. * @@ -218,20 +221,32 @@ class GoogleCloudStorage extends AbstractData } /** - * Purge outdated entries. - * - * @access public - * @param string $namespace - * @param int $time - * @return void + * @inheritDoc */ public function purgeValues($namespace, $time) { - if ($namespace === 'traffic_limiter') { - // TODO implement purging of keys in namespace that are <= $time - // if GCS has no easy way to iterate all keys, consider using the - // self::$_traffic_limiter_cache in a similar way as the other - // implementations. + $prefix = 'config/' . $namespace . '/'; + try { + foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $object) { + $info = $object->info(); + $timeCreated = false; + if (key_exists('timeCreated', $info)) { + $timeCreated = DateTime::createFromFormat(GoogleCloudStorage::DATETIME_FORMAT, $info['timeCreated']); + } + if ($timeCreated && ($timeCreated->getTimestamp() < $time)) { + try { + $object->delete(); + } catch (NotFoundException $e) { + // deleted by another instance. + } + } else { + if (!$timeCreated) { + error_log('failed to parse create timestamp ' . $info['timeCreated'] . ' of object ' . $object->name()); + } + } + } + } catch (NotFoundException $e) { + // no objects in the bucket yet } } diff --git a/tst/Data/GoogleCloudStorageTest.php b/tst/Data/GoogleCloudStorageTest.php index 30a7d5eb..1c5190de 100644 --- a/tst/Data/GoogleCloudStorageTest.php +++ b/tst/Data/GoogleCloudStorageTest.php @@ -43,7 +43,6 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase foreach (self::$_bucket->objects() as $object) { $object->delete(); } - error_reporting(E_ALL); } public static function tearDownAfterClass() @@ -145,17 +144,26 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase $this->_model->setValue($salt, 'salt', 'master'); $storedSalt = $this->_model->getValue('salt', 'master'); $this->assertEquals($salt, $storedSalt); + $this->_model->purgeValues('salt', time() + 60); + $this->assertFalse($this->_model->getValue('salt', 'master')); $client = hash_hmac('sha512', '127.0.0.1', $salt); $expire = time(); $this->_model->setValue($expire, 'traffic_limiter', $client); $storedExpired = $this->_model->getValue('traffic_limiter', $client); $this->assertEquals($expire, $storedExpired); + $this->assertEquals($expire, $storedExpired); + $this->_model->purgeValues('traffic_limiter', time() - 60); + $this->assertEquals($storedExpired, $this->_model->getValue('traffic_limiter', $client)); + $this->_model->purgeValues('traffic_limiter', time() + 60); + $this->assertFalse($this->_model->getValue('traffic_limiter', $client)); $purgeAt = $expire + (15 * 60); $this->_model->setValue($purgeAt, 'purge_limiter', 'at'); $storedPurgedAt = $this->_model->getValue('purge_limiter', 'at'); $this->assertEquals($purgeAt, $storedPurgedAt); + $this->_model->purgeValues('purge_limiter', time() + 60); + $this->assertFalse($this->_model->getValue('purge_limiter', 'at')); } } @@ -431,11 +439,13 @@ class StorageObjectStub extends StorageObject public function __construct(ConnectionInterface $connection, $name, $bucket, $generation = null, array $info = array(), $encryptionKey = null, $encryptionKeySHA256 = null) { - $this->_name = $name; - $this->_bucket = $bucket; - $this->_generation = $generation; - $this->_info = $info; - $this->_connection = $connection; + $this->_name = $name; + $this->_bucket = $bucket; + $this->_generation = $generation; + $this->_info = $info; + $this->_connection = $connection; + $timeCreated = new Datetime(); + $this->_info['metadata']['timeCreated'] = $timeCreated->format(GoogleCloudStorage::DATETIME_FORMAT); } public function acl()