PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/VarnishAdminSocket.php

https://github.com/arjenschat/php-varnish
PHP | 281 lines | 121 code | 51 blank | 109 comment | 15 complexity | 53f6c23256134d0569bd7a94607c9be1 MD5 | raw file
  1. <?php
  2. /**
  3. * Varnish admin socket for executing varnishadm CLI commands.
  4. * @see http://varnish-cache.org/wiki/CLI
  5. * @author Tim Whitlock http://twitter.com/timwhitlock
  6. *
  7. * @todo authentication
  8. * @todo add all short cut methods to commands listed below
  9. * @todo sanitise command parameters, such as regexp
  10. *
  11. * Tested with varnish-2.1.3 SVN 5049:5055;
  12. * CLI commands available as follows:
  13. help [command]
  14. ping [timestamp]
  15. auth response
  16. quit
  17. banner
  18. status
  19. start
  20. stop
  21. stats
  22. vcl.load <configname> <filename>
  23. vcl.inline <configname> <quoted_VCLstring>
  24. vcl.use <configname>
  25. vcl.discard <configname>
  26. vcl.list
  27. vcl.show <configname>
  28. param.show [-l] [<param>]
  29. param.set <param> <value>
  30. purge.url <regexp>
  31. purge <field> <operator> <arg> [&& <field> <oper> <arg>]...
  32. purge.list
  33. */
  34. /**
  35. * varnishadm connection class
  36. */
  37. class VarnishAdminSocket {
  38. /**
  39. * @var resource
  40. */
  41. private $fp;
  42. /**
  43. * @param string host name varnishadm is listening on
  44. */
  45. private $host;
  46. /**
  47. * @param string port varnishadm is listening on
  48. */
  49. private $port;
  50. /**
  51. * Constructor
  52. */
  53. function __construct( $host = '127.0.0.1', $port = 6082 ){
  54. $this->host = $host;
  55. $this->port = $port;
  56. }
  57. /**
  58. * Connect to admin socket
  59. * @param int optional timeout in seconds, defaults to 5; used for connect and reads
  60. * @return string the banner, in case you're interested
  61. */
  62. function connect( $timeout = 5 ){
  63. $this->fp = fsockopen( $this->host, $this->port, $errno, $errstr, $timeout );
  64. if( ! is_resource( $this->fp ) ){
  65. // error would have been raised already by fsockopen
  66. throw new Exception( sprintf('Failed to connect to varnishadm on %s:%s; "%s"', $this->host, $this->port, $errstr ));
  67. }
  68. // set socket options
  69. stream_set_blocking( $this->fp, 1 );
  70. stream_set_timeout( $this->fp, $timeout );
  71. // connecting should give us the varnishadm banner with a 200 code
  72. $banner = $this->read( $code );
  73. if($code == 107){
  74. $challenge = substr($banner, 0, 32);
  75. // change you secret
  76. // TODO: this should be moved to the class __construct
  77. $secret="";
  78. $hash2= hash('sha256', $challenge."\n".$secret.$challenge."\n");
  79. $r=$this->command("auth ".$hash2, $code);
  80. }
  81. elseif( $code !== 200 ){
  82. throw new Exception( sprintf('Bad response from varnishadm on %s:%s', $this->host, $this->port));
  83. }
  84. return $banner;
  85. }
  86. /**
  87. * Write data to the socket input stream
  88. * @param string
  89. * @return bool
  90. */
  91. private function write( $data ){
  92. $bytes = fputs( $this->fp, $data );
  93. if( $bytes !== strlen($data) ){
  94. throw new Exception( sprintf('Failed to write to varnishadm on %s:%s', $this->host, $this->port) );
  95. }
  96. return true;
  97. }
  98. /**
  99. * Write a command to the socket with a trailing line break and get response straight away
  100. * @param string
  101. * @return string
  102. */
  103. public function command( $cmd, &$code, $ok = 200 ){
  104. $cmd and $this->write( $cmd );
  105. $this->write("\n");
  106. $response = $this->read( $code );
  107. if( $code !== $ok ){
  108. $response = implode("\n > ", explode("\n",trim($response) ) );
  109. throw new Exception( sprintf("%s command responded %d:\n > %s", $cmd, $code, $response) );
  110. }
  111. return $response;
  112. }
  113. /**
  114. * @param int reference for reply code
  115. * @return string
  116. */
  117. private function read( &$code ){
  118. $code = 0;
  119. // get bytes until we have either a response code and message length or an end of file
  120. // code should be on first line, so we should get it in one chunk
  121. while ( ! feof($this->fp) ) {
  122. $response = fgets( $this->fp, 1024 );
  123. if( ! $response ){
  124. $meta = stream_get_meta_data($this->fp);
  125. if( $meta['timed_out'] ){
  126. throw new Exception(sprintf('Timed out reading from socket %s:%s',$this->host,$this->port));
  127. }
  128. }
  129. if( preg_match('/^(\d{3}) (\d+)/', $response, $r) ){
  130. $code = (int) $r[1];
  131. $len = (int) $r[2];
  132. break;
  133. }
  134. }
  135. if( ! isset($code) ){
  136. throw new Exception('Failed to get numeric code in response');
  137. }
  138. $response = '';
  139. while ( ! feof($this->fp) && strlen($response) < $len ) {
  140. $response .= fgets( $this->fp, 1024 );
  141. }
  142. return $response;
  143. }
  144. /**
  145. * Brutal close, doesn't send quit command to varnishadm
  146. * @return void
  147. */
  148. public function close(){
  149. is_resource($this->fp) and fclose($this->fp);
  150. $this->fp = null;
  151. }
  152. /**
  153. * Graceful close, sends quit command
  154. * @return void
  155. */
  156. public function quit(){
  157. try {
  158. $this->command('quit', $code, 500 );
  159. }
  160. catch( Exception $Ex ){
  161. // slient fail - force close of socket
  162. }
  163. $this->close();
  164. }
  165. /**
  166. * Shortcut to purge function
  167. * @see http://varnish-cache.org/wiki/Purging
  168. * @param string purge expression in form "<field> <operator> <arg> [&& <field> <oper> <arg>]..."
  169. * @return string
  170. */
  171. public function purge( $expr ){
  172. return $this->command( 'purge '.$expr, $code );
  173. }
  174. /**
  175. * Shortcut to purge.url function
  176. * @see http://varnish-cache.org/wiki/Purging
  177. * @param string url to purge
  178. * @return string
  179. */
  180. public function purge_url( $expr ){
  181. return $this->command( 'purge.url '.$expr, $code );
  182. }
  183. /**
  184. * Shortcut to purge.list function
  185. * @todo should we parse the reponse lines?
  186. * @return array
  187. */
  188. public function purge_list(){
  189. $response = $this->command( 'purge.list', $code );
  190. return explode( "\n",trim($response) );
  191. }
  192. /**
  193. * Test varnish child status
  194. * @return bool whether child is alive
  195. */
  196. public function status(){
  197. try {
  198. $response = $this->command( 'status', $code );
  199. if( ! preg_match('/Child in state (\w+)/', $response, $r ) ) {
  200. return false;
  201. }
  202. return $r[1] === 'running';
  203. }
  204. catch( Exception $Ex ){
  205. return false;
  206. }
  207. }
  208. /**
  209. * @return bool
  210. */
  211. public function stop(){
  212. if( ! $this->status() ){
  213. trigger_error(sprintf('varnish host already stopped on %s:%s', $this->host, $this->port), E_USER_NOTICE);
  214. return true;
  215. }
  216. $this->command( 'stop', $code );
  217. return true;
  218. }
  219. /**
  220. * @return bool
  221. */
  222. public function start(){
  223. if( $this->status() ){
  224. trigger_error(sprintf('varnish host already started on %s:%s', $this->host, $this->port), E_USER_NOTICE);
  225. return true;
  226. }
  227. $this->command( 'start', $code );
  228. return true;
  229. }
  230. }