PageRenderTime 25ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/content/plugins/w3-total-cache/Varnish_Flush.php

https://gitlab.com/karlen/ayo_wp
PHP | 432 lines | 251 code | 70 blank | 111 comment | 58 complexity | cd60af9eef01182e7a3501471dc7d834 MD5 | raw file
  1. <?php
  2. namespace W3TC;
  3. /**
  4. * Class Varnish_Flush
  5. */
  6. class Varnish_Flush {
  7. /**
  8. * Debug flag
  9. *
  10. * @var bool
  11. */
  12. var $_debug = false;
  13. /**
  14. * Varnish servers
  15. *
  16. * @var array
  17. */
  18. var $_servers = array();
  19. /**
  20. * Operation timeout
  21. *
  22. * @var int
  23. */
  24. var $_timeout = 30;
  25. /**
  26. * Advanced cache config
  27. */
  28. var $_config = null;
  29. /**
  30. * Array of already flushed urls
  31. *
  32. * @var array
  33. */
  34. private $queued_urls = array();
  35. private $flush_operation_requested = false;
  36. /**
  37. * PHP5-style constructor
  38. */
  39. function __construct() {
  40. $this->_config = Dispatcher::config();
  41. $this->_debug = $this->_config->get_boolean( 'varnish.debug' );
  42. $this->_servers = $this->_config->get_array( 'varnish.servers' );
  43. $this->_timeout = $this->_config->get_integer( 'timelimit.varnish_purge' );
  44. }
  45. /**
  46. * Purge URI
  47. *
  48. * @param string $url
  49. * @return boolean
  50. */
  51. protected function _purge( $url ) {
  52. @set_time_limit( $this->_timeout );
  53. $return = true;
  54. foreach ( (array) $this->_servers as $server ) {
  55. $response = $this->_request( $server, $url );
  56. if ( is_wp_error( $response ) ) {
  57. $this->_log( $url, sprintf( 'Unable to send request: %s.', implode( '; ', $response->get_error_messages() ) ) );
  58. $return = false;
  59. } elseif ( $response['response']['code'] !== 200 ) {
  60. $this->_log( $url, 'Bad response: ' . $response['response']['status'] );
  61. $return = false;
  62. } else {
  63. $this->_log( $url, 'PURGE OK' );
  64. }
  65. }
  66. return $return;
  67. }
  68. /*
  69. * Sends purge request. Cannt use default wp HTTP implementation
  70. * if we send request to different host than specified in $url
  71. *
  72. * @param $url string
  73. */
  74. function _request( $varnish_server, $url ) {
  75. $parse_url = @parse_url( $url );
  76. if ( !$parse_url || !isset( $parse_url['host'] ) )
  77. return new \WP_Error( 'http_request_failed', 'Unrecognized URL format ' . $url );
  78. $host = $parse_url['host'];
  79. $port = ( isset( $parse_url['port'] ) ? (int) $parse_url['port'] : 80 );
  80. $path = ( !empty( $parse_url['path'] ) ? $parse_url['path'] : '/' );
  81. $query = ( isset( $parse_url['query'] ) ? $parse_url['query'] : '' );
  82. $request_uri = $path . ( $query != '' ? '?' . $query : '' );
  83. if ( strpos( $varnish_server, ':' ) )
  84. list( $varnish_host, $varnish_port ) = explode( ':', $varnish_server );
  85. else {
  86. $varnish_host = $varnish_server;
  87. $varnish_port = 80;
  88. }
  89. // if url host is the same as varnish server - we can use regular
  90. // wordpress http infrastructure, otherwise custom request should be
  91. // sent using fsockopen, since we send request to other server than
  92. // specified by $url
  93. if ( $host == $varnish_host && $port == $varnish_port )
  94. return Util_Http::request( $url, array( 'method' => 'PURGE' ) );
  95. $request_headers_array = array(
  96. sprintf( 'PURGE %s HTTP/1.1', $request_uri ),
  97. sprintf( 'Host: %s', $host ),
  98. sprintf( 'User-Agent: %s', W3TC_POWERED_BY ),
  99. 'Connection: close'
  100. );
  101. $request_headers = implode( "\r\n", $request_headers_array );
  102. $request = $request_headers . "\r\n\r\n";
  103. // log what we are about to do
  104. $this->_log( $url, sprintf( 'Connecting to %s ...', $varnish_host ) );
  105. $this->_log( $url, sprintf( 'PURGE %s HTTP/1.1', $request_uri ) );
  106. $this->_log( $url, sprintf( 'Host: %s', $host ) );
  107. $errno = null;
  108. $errstr = null;
  109. $fp = @fsockopen( $varnish_host, $varnish_port, $errno, $errstr, 10 );
  110. if ( !$fp )
  111. return new \WP_Error( 'http_request_failed', $errno . ': ' . $errstr );
  112. @stream_set_timeout( $fp, 60 );
  113. @fputs( $fp, $request );
  114. $response = '';
  115. while ( !@feof( $fp ) )
  116. $response .= @fgets( $fp, 4096 );
  117. @fclose( $fp );
  118. list( $response_headers, $contents ) = explode( "\r\n\r\n", $response, 2 );
  119. $matches = null;
  120. if ( preg_match( '~^HTTP/1.[01] (\d+)~', $response_headers, $matches ) ) {
  121. $code = (int)$matches[1];
  122. $a = explode( "\n", $response_headers );
  123. $status = ( count( $a ) >= 1 ? $a[0] : '' );
  124. $return = array(
  125. 'response' => array(
  126. 'code' => $code,
  127. 'status' => $status
  128. )
  129. );
  130. return $return;
  131. }
  132. return new \WP_Error( 'http_request_failed',
  133. 'Unrecognized response header' . $response_headers );
  134. }
  135. /**
  136. * Write log entry
  137. *
  138. * @param string $url
  139. * @param string $msg
  140. * @return bool|int
  141. */
  142. function _log( $url, $msg ) {
  143. if ( $this->_debug ) {
  144. $data = sprintf( "[%s] [%s] %s\n", date( 'r' ), $url, $msg );
  145. $data = strtr( $data, '<>', '' );
  146. $filename = Util_Debug::log_filename( 'varnish' );
  147. return @file_put_contents( $filename, $data, FILE_APPEND );
  148. }
  149. return true;
  150. }
  151. /**
  152. * Flush varnish cache
  153. */
  154. function flush() {
  155. $this->flush_operation_requested = true;
  156. return true;
  157. }
  158. private function do_flush() {
  159. if ( !is_network_admin() ) {
  160. $queued_urls[ get_home_url() . '/.*' ] = '*';
  161. // add mirror urls
  162. $queued_urls = Util_PageUrls::complement_with_mirror_urls(
  163. $queued_urls );
  164. foreach ( $queued_urls as $url => $nothing )
  165. $this->_purge( $url );
  166. } else {
  167. // todo: remove. doesnt work for all caches.
  168. // replace with tool to flush network
  169. global $wpdb;
  170. $protocall = Util_Environment::is_https() ? 'https://' : 'http://';
  171. // If WPMU Domain Mapping plugin is installed and active
  172. if ( defined( 'SUNRISE_LOADED' ) && SUNRISE_LOADED && isset( $wpdb->dmtable ) && !empty( $wpdb->dmtable ) ) {
  173. $blogs = $wpdb->get_results( "SELECT {$wpdb->blogs}.domain, {$wpdb->blogs}.path, {$wpdb->dmtable}.domain AS mapped_domain
  174. FROM {$wpdb->dmtable}
  175. RIGHT JOIN {$wpdb->blogs} ON {$wpdb->dmtable}.blog_id = {$wpdb->blogs}.blog_id
  176. WHERE site_id = {$wpdb->siteid}
  177. AND spam = 0
  178. AND deleted = 0
  179. AND archived = '0'
  180. " );
  181. foreach ( $blogs as $blog ) {
  182. if ( !isset( $blog->mapped_domain ) )
  183. $url = $protocall . $blog->domain . ( strlen( $blog->path )>1? '/' . trim( $blog->path, '/' ) : '' ) . '/.*';
  184. else
  185. $url = $protocall . $blog->mapped_domain . '/.*';
  186. $this->_purge( $url );
  187. }
  188. }else {
  189. if ( !Util_Environment::is_wpmu_subdomain() ) {
  190. $this->_purge( get_home_url().'/.*' );
  191. } else {
  192. $blogs = $wpdb->get_results( "
  193. SELECT domain, path
  194. FROM {$wpdb->blogs}
  195. WHERE site_id = '{$wpdb->siteid}'
  196. AND spam = 0
  197. AND deleted = 0
  198. AND archived = '0'
  199. " );
  200. foreach ( $blogs as $blog ) {
  201. $url = $protocall . $blog->domain . ( strlen( $blog->path )>1? '/' . trim( $blog->path, '/' ) : '' ) . '/.*';
  202. $this->_purge( $url );
  203. }
  204. }
  205. }
  206. }
  207. }
  208. /**
  209. * Flushes varnish post cache
  210. *
  211. * @param integer $post_id
  212. * @return boolean
  213. */
  214. function flush_post( $post_id ) {
  215. if ( !$post_id ) {
  216. $post_id = Util_Environment::detect_post_id();
  217. }
  218. if ( $post_id ) {
  219. $full_urls = array();
  220. $post = null;
  221. $terms = array();
  222. $feeds = $this->_config->get_array( 'pgcache.purge.feed.types' );
  223. $limit_post_pages = $this->_config->get_integer( 'pgcache.purge.postpages_limit' );
  224. if ( $this->_config->get_boolean( 'pgcache.purge.terms' ) || $this->_config->get_boolean( 'varnish.pgcache.feed.terms' ) ) {
  225. $taxonomies = get_post_taxonomies( $post_id );
  226. $terms = wp_get_post_terms( $post_id, $taxonomies );
  227. }
  228. switch ( true ) {
  229. case $this->_config->get_boolean( 'pgcache.purge.author' ):
  230. case $this->_config->get_boolean( 'pgcache.purge.archive.daily' ):
  231. case $this->_config->get_boolean( 'pgcache.purge.archive.monthly' ):
  232. case $this->_config->get_boolean( 'pgcache.purge.archive.yearly' ):
  233. case $this->_config->get_boolean( 'pgcache.purge.feed.author' ):
  234. $post = get_post( $post_id );
  235. }
  236. $front_page = get_option( 'show_on_front' );
  237. /**
  238. * Home (Frontpage) URL
  239. */
  240. if ( ( $this->_config->get_boolean( 'pgcache.purge.home' ) && $front_page == 'posts' )||
  241. $this->_config->get_boolean( 'pgcache.purge.front_page' ) ) {
  242. $full_urls = array_merge( $full_urls,
  243. Util_PageUrls::get_frontpage_urls( $limit_post_pages ) );
  244. }
  245. /**
  246. * Home (Post page) URL
  247. */
  248. if ( $this->_config->get_boolean( 'pgcache.purge.home' ) && $front_page != 'posts' ) {
  249. $full_urls = array_merge( $full_urls,
  250. Util_PageUrls::get_postpage_urls( $limit_post_pages ) );
  251. }
  252. /**
  253. * Post URL
  254. */
  255. if ( $this->_config->get_boolean( 'pgcache.purge.post' ) ) {
  256. $full_urls = array_merge( $full_urls, Util_PageUrls::get_post_urls( $post_id ) );
  257. }
  258. /**
  259. * Post comments URLs
  260. */
  261. if ( $this->_config->get_boolean( 'pgcache.purge.comments' ) && function_exists( 'get_comments_pagenum_link' ) ) {
  262. $full_urls = array_merge( $full_urls, Util_PageUrls::get_post_comments_urls( $post_id ) );
  263. }
  264. /**
  265. * Post author URLs
  266. */
  267. if ( $this->_config->get_boolean( 'pgcache.purge.author' ) && $post ) {
  268. $full_urls = array_merge( $full_urls, Util_PageUrls::get_post_author_urls( $post->post_author, $limit_post_pages ) );
  269. }
  270. /**
  271. * Post terms URLs
  272. */
  273. if ( $this->_config->get_boolean( 'pgcache.purge.terms' ) ) {
  274. $full_urls = array_merge( $full_urls, Util_PageUrls::get_post_terms_urls( $terms, $limit_post_pages ) );
  275. }
  276. /**
  277. * Daily archive URLs
  278. */
  279. if ( $this->_config->get_boolean( 'pgcache.purge.archive.daily' ) && $post ) {
  280. $full_urls = array_merge( $full_urls, Util_PageUrls::get_daily_archive_urls( $post, $limit_post_pages ) );
  281. }
  282. /**
  283. * Monthly archive URLs
  284. */
  285. if ( $this->_config->get_boolean( 'pgcache.purge.archive.monthly' ) && $post ) {
  286. $full_urls = array_merge( $full_urls, Util_PageUrls::get_monthly_archive_urls( $post, $limit_post_pages ) );
  287. }
  288. /**
  289. * Yearly archive URLs
  290. */
  291. if ( $this->_config->get_boolean( 'pgcache.purge.archive.yearly' ) && $post ) {
  292. $full_urls = array_merge( $full_urls, Util_PageUrls::get_yearly_archive_urls( $post, $limit_post_pages ) );
  293. }
  294. /**
  295. * Feed URLs
  296. */
  297. if ( $this->_config->get_boolean( 'pgcache.purge.feed.blog' ) ) {
  298. $full_urls = array_merge( $full_urls,
  299. Util_PageUrls::get_feed_urls( $feeds ) );
  300. }
  301. if ( $this->_config->get_boolean( 'pgcache.purge.feed.comments' ) ) {
  302. $full_urls = array_merge( $full_urls, Util_PageUrls::get_feed_comments_urls( $post_id, $feeds ) );
  303. }
  304. if ( $this->_config->get_boolean( 'pgcache.purge.feed.author' ) && $post ) {
  305. $full_urls = array_merge( $full_urls, Util_PageUrls::get_feed_author_urls( $post->post_author, $feeds ) );
  306. }
  307. if ( $this->_config->get_boolean( 'pgcache.purge.feed.terms' ) ) {
  308. $full_urls = array_merge( $full_urls, Util_PageUrls::get_feed_terms_urls( $terms, $feeds ) );
  309. }
  310. /**
  311. * Purge selected pages
  312. */
  313. if ( $this->_config->get_array( 'pgcache.purge.pages' ) ) {
  314. $pages = $this->_config->get_array( 'pgcache.purge.pages' );
  315. $full_urls = array_merge( $full_urls, Util_PageUrls::get_pages_urls( $pages ) );
  316. }
  317. if ( $this->_config->get_string( 'pgcache.purge.sitemap_regex' ) ) {
  318. $sitemap_regex = $this->_config->get_string( 'pgcache.purge.sitemap_regex' );
  319. $full_urls[] = Util_Environment::home_domain_root_url() . '/' . trim( $sitemap_regex, "^$" );
  320. }
  321. /**
  322. * Queue flush
  323. */
  324. if ( count( $full_urls ) ) {
  325. foreach ( $full_urls as $url )
  326. $this->queued_urls[$url] = '*';
  327. // add mirror urls
  328. $this->queued_urls = Util_PageUrls::complement_with_mirror_urls(
  329. $this->queued_urls );
  330. }
  331. return true;
  332. }
  333. return false;
  334. }
  335. /**
  336. * Flush a single url
  337. *
  338. * @param unknown $url
  339. */
  340. function flush_url( $url ) {
  341. $this->_purge( $url );
  342. }
  343. /**
  344. * Flushes global and repeated urls
  345. */
  346. function flush_post_cleanup() {
  347. if ( $this->flush_operation_requested ) {
  348. $this->do_flush();
  349. $count = 999;
  350. $this->flush_operation_requested = false;
  351. $this->queued_urls = array();
  352. } else {
  353. $count = count( $this->queued_urls );
  354. if ( $count > 0 ) {
  355. foreach ( $this->queued_urls as $url => $nothing )
  356. $this->flush_url( $url );
  357. $this->queued_urls = array();
  358. }
  359. }
  360. return $count;
  361. }
  362. }