From ef43ddee0056ed3399f5ae4b60ce0ba11e780b59 Mon Sep 17 00:00:00 2001
From: Olav Morken <olav.morken@uninett.no>
Date: Tue, 31 Mar 2009 06:58:08 +0000
Subject: [PATCH] New metadata handler: serialize

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1451 44740490-163a-0410-bde0-09ae8108e29a
---
 .../MetaDataStorageHandlerSerialize.php       | 251 ++++++++++++++++++
 .../Metadata/MetaDataStorageSource.php        |   2 +
 2 files changed, 253 insertions(+)
 create mode 100644 lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php

diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php
new file mode 100644
index 000000000..702ecab9c
--- /dev/null
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php
@@ -0,0 +1,251 @@
+<?php
+
+/**
+ * Class for handling metadata files in serialized format.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Metadata_MetaDataStorageSource {
+
+	/**
+	 * The file extension we use for our metadata files.
+	 */
+	const EXTENSION = '.serialized';
+
+
+	/**
+	 * The base directory where metadata is stored.
+	 */
+	private $directory;
+
+
+	/**
+	 * Constructor for this metadata handler.
+	 *
+	 * Parses configuration.
+	 *
+	 * @param array $config  The configuration for this metadata handler.
+	 */
+	public function __construct($config) {
+		assert('is_array($config)');
+
+		$globalConfig = SimpleSAML_Configuration::getInstance();
+
+		$cfgHelp = SimpleSAML_Configuration::loadFromArray($config, 'serialize metadata source');
+
+		$this->directory = $cfgHelp->getString('directory');
+
+		/* Resolve this directory relative to the simpleSAMLphp directory (unless it is
+		 * an absolute path).
+		 */
+		$this->directory = $globalConfig->resolvePath($this->directory) . '/';
+	}
+
+
+	/**
+	 * Helper function for retrieving the path of a metadata file.
+	 *
+	 * @param string $entityId  The entity ID.
+	 * @param string $set  The metadata set.
+	 * @return string  The path to the metadata file.
+	 */
+	private function getMetadataPath($entityId, $set) {
+		assert('is_string($entityId)');
+		assert('is_string($set)');
+
+		return $this->directory . '/' . rawurlencode($set) . '/' . rawurlencode($entityId) . self::EXTENSION;
+	}
+
+
+	/**
+	 * Retrieve a list of all available metadata sets.
+	 *
+	 * @return array  An array with the available sets.
+	 */
+	public function getMetadataSets() {
+
+		$ret = array();
+
+		$dh = opendir($this->directory);
+		if ($dh === FALSE) {
+			return $ret;
+		}
+
+		while ( ($entry = readdir($dh)) !== FALSE) {
+
+			if ($entry[0] === '.') {
+				/* Skip '..', '.' and hidden files. */
+				continue;
+			}
+
+			$path = $this->directory . '/' . $entry;
+
+			if (!is_dir($path)) {
+				continue;
+			}
+
+			$ret[] = rawurldecode($entry);
+		}
+
+		closedir($dh);
+
+		return $ret;
+	}
+
+
+	/**
+	 * Retrieve a list of all available metadata for a given set.
+	 *
+	 * @param string $set  The set we are looking for metadata in.
+	 * @return array  An associative array with all the metadata for the given set.
+	 */
+	public function getMetadataSet($set) {
+		assert('is_string($set)');
+
+		$ret = array();
+
+		$dir = $this->directory . '/' . rawurlencode($set);
+		$dh = opendir($dir);
+		if ($dh === FALSE) {
+			return NULL;
+		}
+
+		$extLen = strlen(self::EXTENSION);
+
+		while ( ($file = readdir($dh)) !== FALSE) {
+			if (strlen($file) <= $extLen) {
+				continue;
+			}
+
+			if (substr($file, -$extLen) !== self::EXTENSION) {
+				continue;
+			}
+
+			$entityId = substr($file, 0, -$extLen);
+			$entityId = rawurldecode($entityId);
+
+			$md = $this->getMetaData($entityId, $set);
+			if ($md !== NULL) {
+				$ret[$entityId] = $md;
+			}
+		}
+
+		closedir($dh);
+
+		return $ret;
+	}
+
+
+	/**
+	 * Retrieve a metadata entry.
+	 *
+	 * @param string $entityId  The entityId we are looking up.
+	 * @param string $set  The set we are looking for metadata in.
+	 * @return array  An associative array with metadata for the given entity, or NULL if we are unable to
+	 *         locate the entity.
+	 */
+	public function getMetaData($entityId, $set) {
+		assert('is_string($entityId)');
+		assert('is_string($set)');
+
+		$filePath = $this->getMetadataPath($entityId, $set);
+
+		if (!file_exists($filePath)) {
+			return NULL;
+		}
+
+		$data = file_get_contents($filePath);
+		if ($data === FALSE) {
+			SimpleSAML_Logger::warning('Error reading file ' . $filePath .
+				': ' . SimpleSAML_Utilities::getLastError());
+			return NULL;
+		}
+
+		$data = unserialize($data);
+		if ($data === FALSE) {
+			SimpleSAML_Logger::warning('Error deserializing file: ' . $filePath);
+			return NULL;
+		}
+
+		return $data;
+	}
+
+
+	/**
+	 * Save a metadata entry.
+	 *
+	 * @param string $entityId  The entityId of the metadata entry.
+	 * @param string $set  The metadata set this metadata entry belongs to.
+	 * @param array $metadata  The metadata.
+	 */
+	public function saveMetadata($entityId, $set, $metadata) {
+		assert('is_string($entityId)');
+		assert('is_string($set)');
+		assert('is_array($metadata)');
+
+		$filePath = $this->getMetadataPath($entityId, $set);
+		$newPath = $filePath . '.new';
+
+		$dir = dirname($filePath);
+		if (!is_dir($dir)) {
+			SimpleSAML_Logger::info('Creating directory: ' . $dir);
+			$res = @mkdir($dir, 0777, TRUE);
+			if ($res === FALSE) {
+				SimpleSAML_Logger::error('Failed to create directory ' . $dir .
+					': ' . SimpleSAML_Utilities::getLastError());
+				return FALSE;
+			}
+		}
+
+		$data = serialize($metadata);
+
+		SimpleSAML_Logger::debug('Writing: ' . $newPath);
+
+		$res = file_put_contents($newPath, $data);
+		if ($res === FALSE) {
+			SimpleSAML_Logger::error('Error saving file ' . $newPath .
+				': ' . SimpleSAML_Utilities::getLastError());
+			return FALSE;
+		}
+
+		$res = rename($newPath, $filePath);
+		if ($res === FALSE) {
+			SimpleSAML_Logger::error('Error renaming ' . $newPath . ' to ' . $filePath .
+				': ' . SimpleSAML_Utilities::getLastError());
+			return FALSE;
+		}
+
+
+		return TRUE;
+	}
+
+
+	/**
+	 * Delete a metadata entry.
+	 *
+	 * @param string $entityId  The entityId of the metadata entry.
+	 * @param string $set  The metadata set this metadata entry belongs to.
+	 */
+	public function deleteMetadata($entityId, $set) {
+		assert('is_string($entityId)');
+		assert('is_string($set)');
+
+		$filePath = $this->getMetadataPath($entityId, $set);
+
+		if (!file_exists($filePath)) {
+			SimpleSAML_Logger::warning('Attempted to erase non-existant metadata entry ' .
+				var_export($entityId, TRUE) . ' in set ' . var_export($set, TRUE) . '.');
+			return;
+		}
+
+		$res = unlink($filePath);
+		if ($res === FALSE) {
+			SimpleSAML_Logger::error('Failed to delete file ' . $filePath .
+				': ' . SimpleSAML_Utilities::getLastError());
+		}
+	}
+
+}
+
+?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php
index 07ea1ba7a..0c650d5ab 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php
@@ -67,6 +67,8 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource {
 				return new SimpleSAML_Metadata_MetaDataStorageHandlerXML($sourceConfig);
 			case 'dynamicxml':
 				return new SimpleSAML_Metadata_MetaDataStorageHandlerDynamicXML($sourceConfig);
+			case 'serialize':
+				return new SimpleSAML_Metadata_MetaDataStorageHandlerSerialize($sourceConfig);
 			default:
 				throw new Exception('Invalid metadata source type: "' . $type . '".');
 		}
-- 
GitLab