1<?php
2/*
3The NuSOAP project home is:
4http://sourceforge.net/projects/nusoap/
5
6The primary support for NuSOAP is the mailing list:
7nusoap-general@lists.sourceforge.net
8*/
9
10/**
11* caches instances of the wsdl class
12*
13* @author   Scott Nichol <snichol@users.sourceforge.net>
14* @author	Ingo Fischer <ingo@apollon.de>
15* @version  $Id: class.wsdlcache.php,v 1.7 2007/04/17 16:34:03 snichol Exp $
16* @access public
17*/
18class nusoap_wsdlcache {
19	/**
20	 *	@var resource
21	 *	@access private
22	 */
23	var $fplock;
24	/**
25	 *	@var integer
26	 *	@access private
27	 */
28	var $cache_lifetime;
29	/**
30	 *	@var string
31	 *	@access private
32	 */
33	var $cache_dir;
34	/**
35	 *	@var string
36	 *	@access public
37	 */
38	var $debug_str = '';
39
40	/**
41	* constructor
42	*
43	* @param string $cache_dir directory for cache-files
44	* @param integer $cache_lifetime lifetime for caching-files in seconds or 0 for unlimited
45	* @access public
46	*/
47	function nusoap_wsdlcache($cache_dir='.', $cache_lifetime=0) {
48		$this->fplock = array();
49		$this->cache_dir = $cache_dir != '' ? $cache_dir : '.';
50		$this->cache_lifetime = $cache_lifetime;
51	}
52
53	/**
54	* creates the filename used to cache a wsdl instance
55	*
56	* @param string $wsdl The URL of the wsdl instance
57	* @return string The filename used to cache the instance
58	* @access private
59	*/
60	function createFilename($wsdl) {
61		return $this->cache_dir.'/wsdlcache-' . md5($wsdl);
62	}
63
64	/**
65	* adds debug data to the class level debug string
66	*
67	* @param    string $string debug data
68	* @access   private
69	*/
70	function debug($string){
71		$this->debug_str .= get_class($this).": $string\n";
72	}
73
74	/**
75	* gets a wsdl instance from the cache
76	*
77	* @param string $wsdl The URL of the wsdl instance
78	* @return object wsdl The cached wsdl instance, null if the instance is not in the cache
79	* @access public
80	*/
81	function get($wsdl) {
82		$filename = $this->createFilename($wsdl);
83		if ($this->obtainMutex($filename, "r")) {
84			// check for expired WSDL that must be removed from the cache
85 			if ($this->cache_lifetime > 0) {
86				if (file_exists($filename) && (time() - filemtime($filename) > $this->cache_lifetime)) {
87					unlink($filename);
88					$this->debug("Expired $wsdl ($filename) from cache");
89					$this->releaseMutex($filename);
90					return null;
91  				}
92			}
93			// see what there is to return
94			if (!file_exists($filename)) {
95				$this->debug("$wsdl ($filename) not in cache (1)");
96				$this->releaseMutex($filename);
97				return null;
98			}
99			$fp = @fopen($filename, "r");
100			if ($fp) {
101				$s = implode("", @file($filename));
102				fclose($fp);
103				$this->debug("Got $wsdl ($filename) from cache");
104			} else {
105				$s = null;
106				$this->debug("$wsdl ($filename) not in cache (2)");
107			}
108			$this->releaseMutex($filename);
109			return (!is_null($s)) ? unserialize($s) : null;
110		} else {
111			$this->debug("Unable to obtain mutex for $filename in get");
112		}
113		return null;
114	}
115
116	/**
117	* obtains the local mutex
118	*
119	* @param string $filename The Filename of the Cache to lock
120	* @param string $mode The open-mode ("r" or "w") or the file - affects lock-mode
121	* @return boolean Lock successfully obtained ?!
122	* @access private
123	*/
124	function obtainMutex($filename, $mode) {
125		if (isset($this->fplock[md5($filename)])) {
126			$this->debug("Lock for $filename already exists");
127			return false;
128		}
129		$this->fplock[md5($filename)] = fopen($filename.".lock", "w");
130		if ($mode == "r") {
131			return flock($this->fplock[md5($filename)], LOCK_SH);
132		} else {
133			return flock($this->fplock[md5($filename)], LOCK_EX);
134		}
135	}
136
137	/**
138	* adds a wsdl instance to the cache
139	*
140	* @param object wsdl $wsdl_instance The wsdl instance to add
141	* @return boolean WSDL successfully cached
142	* @access public
143	*/
144	function put($wsdl_instance) {
145		$filename = $this->createFilename($wsdl_instance->wsdl);
146		$s = serialize($wsdl_instance);
147		if ($this->obtainMutex($filename, "w")) {
148			$fp = fopen($filename, "w");
149			if (! $fp) {
150				$this->debug("Cannot write $wsdl_instance->wsdl ($filename) in cache");
151				$this->releaseMutex($filename);
152				return false;
153			}
154			fputs($fp, $s);
155			fclose($fp);
156			$this->debug("Put $wsdl_instance->wsdl ($filename) in cache");
157			$this->releaseMutex($filename);
158			return true;
159		} else {
160			$this->debug("Unable to obtain mutex for $filename in put");
161		}
162		return false;
163	}
164
165	/**
166	* releases the local mutex
167	*
168	* @param string $filename The Filename of the Cache to lock
169	* @return boolean Lock successfully released
170	* @access private
171	*/
172	function releaseMutex($filename) {
173		$ret = flock($this->fplock[md5($filename)], LOCK_UN);
174		fclose($this->fplock[md5($filename)]);
175		unset($this->fplock[md5($filename)]);
176		if (! $ret) {
177			$this->debug("Not able to release lock for $filename");
178		}
179		return $ret;
180	}
181
182	/**
183	* removes a wsdl instance from the cache
184	*
185	* @param string $wsdl The URL of the wsdl instance
186	* @return boolean Whether there was an instance to remove
187	* @access public
188	*/
189	function remove($wsdl) {
190		$filename = $this->createFilename($wsdl);
191		if (!file_exists($filename)) {
192			$this->debug("$wsdl ($filename) not in cache to be removed");
193			return false;
194		}
195		// ignore errors obtaining mutex
196		$this->obtainMutex($filename, "w");
197		$ret = unlink($filename);
198		$this->debug("Removed ($ret) $wsdl ($filename) from cache");
199		$this->releaseMutex($filename);
200		return $ret;
201	}
202}
203
204/**
205 * For backward compatibility
206 */
207class wsdlcache extends nusoap_wsdlcache {
208}
209?>
210