TimeSync.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_TimeSync
  17. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @version $Id$
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /**
  22. * Zend_Loader
  23. */
  24. require_once 'Zend/Loader.php';
  25. /**
  26. * Zend_Date
  27. */
  28. require_once 'Zend/Date.php';
  29. /**
  30. * @category Zend
  31. * @package Zend_TimeSync
  32. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. class Zend_TimeSync implements IteratorAggregate
  36. {
  37. /**
  38. * Set the default timeserver protocol to "Ntp". This will be called
  39. * when no protocol is specified
  40. */
  41. const DEFAULT_PROTOCOL = 'Ntp';
  42. /**
  43. * Contains array of timeserver objects
  44. *
  45. * @var array
  46. */
  47. protected $_timeservers = array();
  48. /**
  49. * Holds a reference to the timeserver that is currently being used
  50. *
  51. * @var object
  52. */
  53. protected $_current;
  54. /**
  55. * Allowed timeserver schemes
  56. *
  57. * @var array
  58. */
  59. protected $_allowedSchemes = array(
  60. 'Ntp',
  61. 'Sntp'
  62. );
  63. /**
  64. * Configuration array, set using the constructor or using
  65. * ::setOptions() or ::setOption()
  66. *
  67. * @var array
  68. */
  69. public static $options = array(
  70. 'timeout' => 1
  71. );
  72. /**
  73. * Zend_TimeSync constructor
  74. *
  75. * @param string|array $target - OPTIONAL single timeserver, or an array of timeservers.
  76. * @param string $alias - OPTIONAL an alias for this timeserver
  77. * @return object
  78. */
  79. public function __construct($target = null, $alias = null)
  80. {
  81. if ($target !== null) {
  82. $this->addServer($target, $alias);
  83. }
  84. }
  85. /**
  86. * getIterator() - return an iteratable object for use in foreach and the like,
  87. * this completes the IteratorAggregate interface
  88. *
  89. * @return ArrayObject
  90. */
  91. public function getIterator()
  92. {
  93. return new ArrayObject($this->_timeservers);
  94. }
  95. /**
  96. * Add a timeserver or multiple timeservers
  97. *
  98. * Server should be a single string representation of a timeserver,
  99. * or a structured array listing multiple timeservers.
  100. *
  101. * If you provide an array of timeservers in the $target variable,
  102. * $alias will be ignored. you can enter these as the array key
  103. * in the provided array, which should be structured as follows:
  104. *
  105. * <code>
  106. * $example = array(
  107. * 'server_a' => 'ntp://127.0.0.1',
  108. * 'server_b' => 'ntp://127.0.0.1:123',
  109. * 'server_c' => 'ntp://[2000:364:234::2.5]',
  110. * 'server_d' => 'ntp://[2000:364:234::2.5]:123'
  111. * );
  112. * </code>
  113. *
  114. * If no port number has been suplied, the default matching port
  115. * number will be used.
  116. *
  117. * Supported protocols are:
  118. * - ntp
  119. * - sntp
  120. *
  121. * @param string|array $target - Single timeserver, or an array of timeservers.
  122. * @param string $alias - OPTIONAL an alias for this timeserver
  123. * @throws Zend_TimeSync_Exception
  124. */
  125. public function addServer($target, $alias = null)
  126. {
  127. if (is_array($target)) {
  128. foreach ($target as $key => $server) {
  129. $this->_addServer($server, $key);
  130. }
  131. } else {
  132. $this->_addServer($target, $alias);
  133. }
  134. }
  135. /**
  136. * Sets the value for the given options
  137. *
  138. * This will replace any currently defined options.
  139. *
  140. * @param array $options - An array of options to be set
  141. */
  142. public static function setOptions(array $options)
  143. {
  144. foreach ($options as $key => $value) {
  145. Zend_TimeSync::$options[$key] = $value;
  146. }
  147. }
  148. /**
  149. * Marks a nameserver as current
  150. *
  151. * @param string|integer $alias - The alias from the timeserver to set as current
  152. * @throws Zend_TimeSync_Exception
  153. */
  154. public function setServer($alias)
  155. {
  156. if (isset($this->_timeservers[$alias]) === true) {
  157. $this->_current = $this->_timeservers[$alias];
  158. } else {
  159. require_once 'Zend/TimeSync/Exception.php';
  160. throw new Zend_TimeSync_Exception("'$alias' does not point to valid timeserver");
  161. }
  162. }
  163. /**
  164. * Returns the value to the option
  165. *
  166. * @param string $key - The option's identifier
  167. * @return mixed
  168. * @throws Zend_TimeSync_Exception
  169. */
  170. public static function getOptions($key = null)
  171. {
  172. if ($key == null) {
  173. return Zend_TimeSync::$options;
  174. }
  175. if (isset(Zend_TimeSync::$options[$key]) === true) {
  176. return Zend_TimeSync::$options[$key];
  177. } else {
  178. require_once 'Zend/TimeSync/Exception.php';
  179. throw new Zend_TimeSync_Exception("'$key' does not point to valid option");
  180. }
  181. }
  182. /**
  183. * Return a specified timeserver by alias
  184. * If no alias is given it will return the current timeserver
  185. *
  186. * @param string|integer $alias - The alias from the timeserver to return
  187. * @return object
  188. * @throws Zend_TimeSync_Exception
  189. */
  190. public function getServer($alias = null)
  191. {
  192. if ($alias === null) {
  193. if (isset($this->_current) && $this->_current !== false) {
  194. return $this->_current;
  195. } else {
  196. require_once 'Zend/TimeSync/Exception.php';
  197. throw new Zend_TimeSync_Exception('there is no timeserver set');
  198. }
  199. }
  200. if (isset($this->_timeservers[$alias]) === true) {
  201. return $this->_timeservers[$alias];
  202. } else {
  203. require_once 'Zend/TimeSync/Exception.php';
  204. throw new Zend_TimeSync_Exception("'$alias' does not point to valid timeserver");
  205. }
  206. }
  207. /**
  208. * Returns information sent/returned from the current timeserver
  209. *
  210. * @return array
  211. */
  212. public function getInfo()
  213. {
  214. return $this->getServer()->getInfo();
  215. }
  216. /**
  217. * Query the timeserver list using the fallback mechanism
  218. *
  219. * If there are multiple servers listed, this method will act as a
  220. * facade and will try to return the date from the first server that
  221. * returns a valid result.
  222. *
  223. * @param $locale - OPTIONAL locale
  224. * @return object
  225. * @throws Zend_TimeSync_Exception
  226. */
  227. public function getDate($locale = null)
  228. {
  229. require_once 'Zend/TimeSync/Exception.php';
  230. foreach ($this->_timeservers as $alias => $server) {
  231. $this->_current = $server;
  232. try {
  233. return $server->getDate($locale);
  234. } catch (Zend_TimeSync_Exception $e) {
  235. if (!isset($masterException)) {
  236. $masterException = new Zend_TimeSync_Exception('all timeservers are bogus');
  237. }
  238. $masterException->addException($e);
  239. }
  240. }
  241. throw $masterException;
  242. }
  243. /**
  244. * Adds a timeserver object to the timeserver list
  245. *
  246. * @param string|array $target - Single timeserver, or an array of timeservers.
  247. * @param string $alias - An alias for this timeserver
  248. */
  249. protected function _addServer($target, $alias)
  250. {
  251. if ($pos = strpos($target, '://')) {
  252. $protocol = substr($target, 0, $pos);
  253. $adress = substr($target, $pos + 3);
  254. } else {
  255. $adress = $target;
  256. $protocol = self::DEFAULT_PROTOCOL;
  257. }
  258. if ($pos = strrpos($adress, ':')) {
  259. $posbr = strpos($adress, ']');
  260. if ($posbr and ($pos > $posbr)) {
  261. $port = substr($adress, $pos + 1);
  262. $adress = substr($adress, 0, $pos);
  263. } else if (!$posbr and $pos) {
  264. $port = substr($adress, $pos + 1);
  265. $adress = substr($adress, 0, $pos);
  266. } else {
  267. $port = null;
  268. }
  269. } else {
  270. $port = null;
  271. }
  272. $protocol = ucfirst(strtolower($protocol));
  273. if (!in_array($protocol, $this->_allowedSchemes)) {
  274. require_once 'Zend/TimeSync/Exception.php';
  275. throw new Zend_TimeSync_Exception("'$protocol' is not a supported protocol");
  276. }
  277. $className = 'Zend_TimeSync_' . $protocol;
  278. Zend_Loader::loadClass($className);
  279. $timeServerObj = new $className($adress, $port);
  280. $this->_timeservers[$alias] = $timeServerObj;
  281. }
  282. }