ConnectionParameters.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. /*
  3. * This file is part of the Predis package.
  4. *
  5. * (c) Daniele Alessandri <suppakilla@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Predis;
  11. use Predis\IConnectionParameters;
  12. use Predis\Options\IOption;
  13. /**
  14. * Handles parsing and validation of connection parameters.
  15. *
  16. * @author Daniele Alessandri <suppakilla@gmail.com>
  17. */
  18. class ConnectionParameters implements IConnectionParameters
  19. {
  20. private static $defaultParameters;
  21. private static $validators;
  22. private $parameters;
  23. private $userDefined;
  24. /**
  25. * @param string|array Connection parameters in the form of an URI string or a named array.
  26. */
  27. public function __construct($parameters = array())
  28. {
  29. self::ensureDefaults();
  30. if (!is_array($parameters)) {
  31. $parameters = $this->parseURI($parameters);
  32. }
  33. $this->userDefined = array_keys($parameters);
  34. $this->parameters = $this->filter($parameters) + self::$defaultParameters;
  35. }
  36. /**
  37. * Ensures that the default values and validators are initialized.
  38. */
  39. private static function ensureDefaults()
  40. {
  41. if (!isset(self::$defaultParameters)) {
  42. self::$defaultParameters = array(
  43. 'scheme' => 'tcp',
  44. 'host' => '127.0.0.1',
  45. 'port' => 6379,
  46. 'database' => null,
  47. 'password' => null,
  48. 'connection_async' => false,
  49. 'connection_persistent' => false,
  50. 'connection_timeout' => 5.0,
  51. 'read_write_timeout' => null,
  52. 'alias' => null,
  53. 'weight' => null,
  54. 'path' => null,
  55. 'iterable_multibulk' => false,
  56. 'throw_errors' => true,
  57. );
  58. }
  59. if (!isset(self::$validators)) {
  60. $bool = function($value) { return (bool) $value; };
  61. $float = function($value) { return (float) $value; };
  62. $int = function($value) { return (int) $value; };
  63. self::$validators = array(
  64. 'port' => $int,
  65. 'connection_async' => $bool,
  66. 'connection_persistent' => $bool,
  67. 'connection_timeout' => $float,
  68. 'read_write_timeout' => $float,
  69. 'iterable_multibulk' => $bool,
  70. 'throw_errors' => $bool,
  71. );
  72. }
  73. }
  74. /**
  75. * Defines a default value and a validator for the specified parameter.
  76. *
  77. * @param string $parameter Name of the parameter.
  78. * @param mixed $default Default value or an instance of IOption.
  79. * @param mixed $callable A validator callback.
  80. */
  81. public static function define($parameter, $default, $callable = null)
  82. {
  83. self::ensureDefaults();
  84. self::$defaultParameters[$parameter] = $default;
  85. if ($default instanceof IOption) {
  86. self::$validators[$parameter] = $default;
  87. return;
  88. }
  89. if (!isset($callable)) {
  90. unset(self::$validators[$parameter]);
  91. return;
  92. }
  93. if (!is_callable($callable)) {
  94. throw new \InvalidArgumentException(
  95. "The validator for $parameter must be a callable object"
  96. );
  97. }
  98. self::$validators[$parameter] = $callable;
  99. }
  100. /**
  101. * Undefines the default value and validator for the specified parameter.
  102. *
  103. * @param string $parameter Name of the parameter.
  104. */
  105. public static function undefine($parameter)
  106. {
  107. self::ensureDefaults();
  108. unset(self::$defaultParameters[$parameter], self::$validators[$parameter]);
  109. }
  110. /**
  111. * Parses an URI string and returns an array of connection parameters.
  112. *
  113. * @param string $uri Connection string.
  114. * @return array
  115. */
  116. private function parseURI($uri)
  117. {
  118. if (stripos($uri, 'unix') === 0) {
  119. // Hack to support URIs for UNIX sockets with minimal effort.
  120. $uri = str_ireplace('unix:///', 'unix://localhost/', $uri);
  121. }
  122. if (($parsed = @parse_url($uri)) === false || !isset($parsed['host'])) {
  123. throw new ClientException("Invalid URI: $uri");
  124. }
  125. if (isset($parsed['query'])) {
  126. foreach (explode('&', $parsed['query']) as $kv) {
  127. @list($k, $v) = explode('=', $kv);
  128. $parsed[$k] = $v;
  129. }
  130. unset($parsed['query']);
  131. }
  132. return $parsed;
  133. }
  134. /**
  135. * Validates and converts each value of the connection parameters array.
  136. *
  137. * @param array $parameters Connection parameters.
  138. * @return array
  139. */
  140. private function filter(Array $parameters)
  141. {
  142. if (count($parameters) > 0) {
  143. $validators = array_intersect_key(self::$validators, $parameters);
  144. foreach ($validators as $parameter => $validator) {
  145. $parameters[$parameter] = $validator($parameters[$parameter]);
  146. }
  147. }
  148. return $parameters;
  149. }
  150. /**
  151. * {@inheritdoc}
  152. */
  153. public function __get($parameter)
  154. {
  155. $value = $this->parameters[$parameter];
  156. if ($value instanceof IOption) {
  157. $this->parameters[$parameter] = ($value = $value->getDefault());
  158. }
  159. return $value;
  160. }
  161. /**
  162. * {@inheritdoc}
  163. */
  164. public function __isset($parameter)
  165. {
  166. return isset($this->parameters[$parameter]);
  167. }
  168. /**
  169. * Checks if the specified parameter has been set by the user.
  170. *
  171. * @param string $parameter Name of the parameter.
  172. * @return Boolean
  173. */
  174. public function isSetByUser($parameter)
  175. {
  176. return in_array($parameter, $this->userDefined);
  177. }
  178. /**
  179. * {@inheritdoc}
  180. */
  181. protected function getBaseURI()
  182. {
  183. if ($this->scheme === 'unix') {
  184. return "{$this->scheme}://{$this->path}";
  185. }
  186. return "{$this->scheme}://{$this->host}:{$this->port}";
  187. }
  188. /**
  189. * Returns the URI parts that must be omitted when calling __toString().
  190. *
  191. * @return array
  192. */
  193. protected function getDisallowedURIParts()
  194. {
  195. return array('scheme', 'host', 'port', 'password', 'path');
  196. }
  197. /**
  198. * {@inheritdoc}
  199. */
  200. public function toArray()
  201. {
  202. return $this->parameters;
  203. }
  204. /**
  205. * Returns a string representation of the parameters.
  206. *
  207. * @return string
  208. */
  209. public function __toString()
  210. {
  211. $query = array();
  212. $parameters = $this->toArray();
  213. $reject = $this->getDisallowedURIParts();
  214. foreach ($this->userDefined as $param) {
  215. if (in_array($param, $reject) || !isset($parameters[$param])) {
  216. continue;
  217. }
  218. $value = $parameters[$param];
  219. $query[] = "$param=" . ($value === false ? '0' : $value);
  220. }
  221. if (count($query) === 0) {
  222. return $this->getBaseURI();
  223. }
  224. return $this->getBaseURI() . '/?' . implode('&', $query);
  225. }
  226. /**
  227. * {@inheritdoc}
  228. */
  229. public function __sleep()
  230. {
  231. return array('parameters', 'userDefined');
  232. }
  233. /**
  234. * {@inheritdoc}
  235. */
  236. public function __wakeup()
  237. {
  238. self::ensureDefaults();
  239. }
  240. }